package com.xbongbong.paas.elasticsearch.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.ext.ConditionsContainerExt;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.constant.EsNormalConstant;
import com.xbongbong.paas.enums.AddressEnum;
import com.xbongbong.paas.enums.AggTypeEnum;
import com.xbongbong.paas.enums.BelongEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DateDiffTypeEnum;
import com.xbongbong.paas.enums.DateTimeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.pojo.ShareConditionFormatPojo;
import com.xbongbong.paas.pojo.ShareConditionGroupPojo;
import com.xbongbong.paas.pojo.ShareConditionListPojo;
import com.xbongbong.paas.pojo.ShareConditionPojo;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CalendarUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.PaasDateUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.QueryIgnore;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.customer.pojo.BirthdayPojo;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.domain.entity.UpdateDataValueEntity;
import com.xbongbong.pro.enums.RelTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.BiErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.es.pojo.EsScriptConditionPojo;
import com.xbongbong.pro.es.pojo.EsScriptPojo;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.enums.AdvancedComputingFirstEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.DateTypeEnum;
import com.xbongbong.pro.statistic.enums.DateWayEnum;
import com.xbongbong.pro.statistic.enums.NormalTypeEnum;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.saas.base.EnumBase;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.BirthdayFilterEnum;
import com.xbongbong.saas.enums.BirthdayTypeEnum;
import com.xbongbong.saas.enums.ListSearchEnum;
import com.xbongbong.saas.enums.UserTeamEnum;
import com.xbongbong.saas.enums.VisibleRangeEnum;
import com.xbongbong.saas.enums.WarningSearchEnum;
import com.xbongbong.saas.enums.WorkOrderStatusEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.AllFieldEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.CompetitorEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.DistributorContactEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.business.SupplierContactEnum;
import com.xbongbong.saas.enums.subform.CompetitorTeamEnum;
import com.xbongbong.saas.enums.subform.ProductStockSubFormEnum;
import com.xbongbong.saas.enums.subform.ProductTeamEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.enums.subform.SubFormTransferEnum;
import com.xbongbong.saas.enums.subform.VisibleRangeTeamEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.join.aggregations.ChildrenAggregationBuilder;
import org.elasticsearch.join.aggregations.JoinAggregationBuilders;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.MaxAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.MinAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ValueCountAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.SumBucketPipelineAggregationBuilder;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.scriptQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * ES解析工具类
 * 创建时间： 2018/9/25 17:26
 * 修改时间： 2018/9/25 17:26 梁鲁江
 *
 * @author 梁鲁江
 */
public class EsUtil {

    private static final Logger LOG = LoggerFactory.getLogger(EsUtil.class);

    private static EsHelper esHelper = new EsHelper();

    /**
     * 没有data字段的
     */
    private static final String NO_DATA_COLUMNS = "dataId,corpid,appId,menuId,formId,serialNo,creatorId,ownerId,del,addTime,updateTime";
    /**
     * 没有流水号，更新时间、添加时间
     */
    private static final String SYSTEM_COLUMNS = "dataId,corpid,appId,menuId,formId,del";

    private static final String NO_DATA_SUB_FORM_COLUMNS = "dataId,corpid,attr,del,addTime,updateTime";

    private static final int CONDITION_TIME_LENGTH = 1;
    //TODO 业务移出去之后，去使用MathEnum
    private static final String ADD = "ADD";
    private static final String SUBTRACT = "SUBTRACT";
    public static final String DATE_DIFF = "DATE_DIFF";
    private static final String MAX = "MAX";
    private static final String MIN = "MIN";
    private static final String SUM = "SUM";
    private static final String MULTIPLY = "MULTIPLY";
    private static final String DIVIDE = "DIVIDE";
    private static final String AVERAGE = "AVERAGE";

    public static SearchRequest simplePackageForQueryForPage(IndexTypeEnum indexTypeEnum, BoolQueryBuilder boolQueryBuilder, List<String> fieldList, int page, int size) {
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        EsUtil.setFieldList(sourceBuilder, fieldList);
        EsUtil.setPage(sourceBuilder,page,size);
        searchRequest.source(sourceBuilder);
        return searchRequest;
    }

    /**
     * Description: 拼接共享权限条件到es查询
     *
     * @param shareConditions  共享权限条件
     * @param boolQueryBuilder
     * @param corpid           公司id
     * @param businessType     业务类型
     * @param fromThrough
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2023/3/7 10:16
     * @since
     */
    public static void parseSharePermissionCondition(BoolQueryBuilder boolQueryBuilder, ShareConditionFormatPojo shareConditionFormatPojo, String corpid, Integer businessType, Boolean fromThrough) throws XbbException {

        if (Objects.isNull(shareConditionFormatPojo)) {
            return;
        }

        List<ShareConditionListPojo> shareConditions = shareConditionFormatPojo.getShareConditionListPojos();
        List<ConditionsEntityExt> permissionConditions = shareConditionFormatPojo.getPermissionConditions();
        if(CollectionUtils.isEmpty(permissionConditions)){
            //没有团队条件及最大数据权限，不用拼接共享规则
            return;
        }

        businessType = (Objects.isNull(businessType) || Objects.equals(BasicConstant.ZERO, businessType)) ? XbbRefTypeEnum.PAAS.getCode() : businessType;

        if ((CollectionsUtil.isEmpty(shareConditions) && CollectionsUtil.isNotEmpty(permissionConditions)) || fromThrough) {
            // 只有基础权限的封装, 或者来着穿透的只封装基础数据权限
            parseCondition(boolQueryBuilder, permissionConditions, null, corpid, businessType);
        } else if (CollectionsUtil.isNotEmpty(shareConditions) && CollectionsUtil.isNotEmpty(permissionConditions)) {
            // 有基础权限，又有共享权限的封装
            // 共享条件封装
            for (ShareConditionListPojo shareConditionListPojo : shareConditions) {
                List<ShareConditionGroupPojo> shareConditionGroupPojos = shareConditionListPojo.getShareConditionGroupPojos();

                for (ShareConditionGroupPojo shareConditionGroupPojo : shareConditionGroupPojos) {
                    // 一组条件
                    BoolQueryBuilder shareGroupBoolQuery = boolQuery();

                    shareGroupBoolQuery.filter(termQuery(ParameterConstant.FORMID, shareConditionGroupPojo.getFormId()));

                    String operator = shareConditionGroupPojo.getOperator();
                    List<ShareConditionPojo> shareConditionPojos = shareConditionGroupPojo.getShareConditionPojos();

                    if (Objects.equals(operator, RelTypeEnum.AND.getAlias())) {
                        // 且
                        for (ShareConditionPojo shareConditionPojo : shareConditionPojos) {
                            if (CollectionsUtil.isNotEmpty(shareConditionPojo.getCondititonList())) {
                                // 且
                                BoolQueryBuilder shareAndBoolQuery = boolQuery();
                                parseBaseCondition(shareAndBoolQuery, shareConditionPojo.getCondititonList(), corpid, businessType);

                                shareGroupBoolQuery.filter(shareAndBoolQuery);
                            } else if (CollectionsUtil.isNotEmpty(shareConditionPojo.getShouldConditionList())) {
                                // 或
                                BoolQueryBuilder shareOrBoolQuery = boolQuery();
                                for (ConditionsEntityExt conditionsEntityExt : shareConditionPojo.getShouldConditionList()) {
                                    BoolQueryBuilder shouldBoolQuery = boolQuery();
//                                conditionsEntityExt.setShouldFlag(true);
                                    parseSingleBaseCondition(shouldBoolQuery, corpid, businessType, conditionsEntityExt);

                                    shareOrBoolQuery.should(shouldBoolQuery);
                                }
                                shareOrBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);

                                shareGroupBoolQuery.filter(shareOrBoolQuery);

                            }

                        }

                    } else {
                        // 或
                        for (ShareConditionPojo shareConditionPojo : shareConditionPojos) {

                            if (CollectionsUtil.isNotEmpty(shareConditionPojo.getCondititonList())) {
                                // 且
                                BoolQueryBuilder shareAndBoolQuery = boolQuery();
                                parseCondition(shareAndBoolQuery, shareConditionPojo.getCondititonList(), null, corpid, businessType);

                                shareGroupBoolQuery.should(shareAndBoolQuery);

                            } else if (CollectionsUtil.isNotEmpty(shareConditionPojo.getShouldConditionList())) {
                                // 或
                                BoolQueryBuilder shareOrBoolQuery = boolQuery();
                                for (ConditionsEntityExt conditionsEntityExt : shareConditionPojo.getShouldConditionList()) {
                                    BoolQueryBuilder shouldBoolQuery = boolQuery();
//                                conditionsEntityExt.setShouldFlag(true);
                                    parseSingleBaseCondition(shouldBoolQuery, corpid, businessType, conditionsEntityExt);

                                    shareOrBoolQuery.should(shouldBoolQuery);
                                }
                                shareOrBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);

                                shareGroupBoolQuery.should(shareOrBoolQuery);
                            }
                        }
                        shareGroupBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);

                    }

                    // 一组条件为或
                    boolQueryBuilder.should(shareGroupBoolQuery);

                }

                // 基础数据权限
                BoolQueryBuilder permissionBool = boolQuery();
                parseCondition(permissionBool, permissionConditions, null, corpid, businessType);
                boolQueryBuilder.should(permissionBool);
            }


            boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        }


    }


    public String getAttrByFiledType(ConditionsEntityExt condition){
        String attr;
        if(FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getAlias())) {
            attr = "data." + condition.getAttr() + ".keyword";
        } else {
            attr = "data." + condition.getAttr();
        }
        return attr;
    }
    /**
     * 解析查询条件
     * @param boolQueryBuilder es查询条件载体
     * @param conditionList 查询条件集合
     * @param rel 任一 或 全部
     * @param corpid
     * @param businessType 业务索引 当前唯一用途协同团队筛选
     */
    /**
     * 解析查询条件
     * @param boolQueryBuilder es查询条件载体
     * @param conditionList 查询条件集合
     * @param rel 任一 或 全部
     * @param corpid
     * @param businessType 业务索引 当前唯一用途协同团队筛选
     */
    public static void parseCondition(BoolQueryBuilder boolQueryBuilder, List<ConditionsEntityExt> conditionList, String rel,String corpid,Integer businessType) throws XbbException{
        businessType = (Objects.isNull(businessType) || Objects.equals(BasicConstant.ZERO, businessType)) ? XbbRefTypeEnum.PAAS.getCode() : businessType;
        if (conditionList != null) {
            parseBaseCondition(boolQueryBuilder, conditionList, corpid, businessType);
        }
    }

    /**
     * Description: 拼接基础的条件
     * @param boolQueryBuilder es查询条件载体
	 * @param conditionList 查询条件
	 * @param corpid 公司id
	 * @param businessType 业务
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2023/3/7 10:05
     * @since
     */
    public static void parseBaseCondition(BoolQueryBuilder boolQueryBuilder, List<ConditionsEntityExt> conditionList, String corpid, Integer businessType) throws XbbException {
        for (ConditionsEntityExt condition : conditionList){
            parseSingleBaseCondition(boolQueryBuilder, corpid, businessType, condition);
        }
    }

    public static void parseSingleBaseCondition(BoolQueryBuilder boolQueryBuilder, String corpid, Integer businessType, ConditionsEntityExt condition) throws XbbException {
        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
        if (Objects.isNull(conditionEnum)) {
            return;
        }
        if (emptyCheck(condition)){
            return;
        }

        //如果是子表单，非特殊子表单不应该拼接到boolQueryBuilder
        if (Objects.nonNull(businessType) && Objects.nonNull(condition) && Objects.nonNull(condition.getAttr()) && condition.getAttr().contains(FieldTypeEnum.SUB_FORM.getEsalias())
                && !EsHelper.isSpecialSubForm(condition.getAttr(), businessType)){
            IndexTypeEnum subIndexByCode = IndexTypeEnum.getSubIndexByCode(businessType);
            BoolQueryBuilder subBoolQuery = boolQuery();
            parseSubFormBaseCondition(subBoolQuery, condition, businessType);
            HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(subIndexByCode.getType(), subBoolQuery, ScoreMode.Max);

            boolQueryBuilder.filter(hasChildQueryBuilder);
            return;
        }

        getValueByDate(condition);
        Integer fieldType = condition.getFieldType();
        String attr = condition.getAttr();
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.UNKNOWN;
        Boolean teamSearch = !Objects.isNull(businessType) && (FieldTypeEnum.OWNERID.getType().equals(fieldType) || FieldTypeEnum.COUSERID.getType().equals(fieldType) || FieldTypeEnum.TEAM_USER.getType().equals(fieldType) || FieldTypeEnum.TEAM_USER_TYPE.getType().equals(fieldType) || FieldTypeEnum.PRE_OWNER_ID.getType().equals(fieldType));
        Boolean copySearch = false;
        Boolean workOrderTimeOut = false;
        boolean productWarehouseSearch = Objects.equals(FieldTypeEnum.WAREHOUSE_ID.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.WAREHOUSE_CHECKED.getType(), condition.getFieldType());
        boolean knowledge = Objects.equals(businessType,XbbRefTypeEnum.KNOWLEDGE_BASE.getCode());
        boolean birthdaySearch = false;
        boolean visibleRangeTeamSearch = XbbRefTypeEnum.hasVisibleRangeBusiness().contains(businessType) && (Objects.equals(attr, VisibleRangeEnum.VISIBLE_DEPT.getAttr()) || Objects.equals(attr,VisibleRangeEnum.VISIBLE_USER.getAttr()));
        boolean productTeamSearch = Objects.equals(businessType,XbbRefTypeEnum.PRODUCT.getCode()) && (Objects.equals(attr,ProductEnum.VISBLE_DEPT.getAttr()) || Objects.equals(attr,ProductEnum.VISBLE_USER.getAttr()));
        // 竞争对手可见人，可见部门筛选
        boolean competitorTeamSearch = Objects.equals(businessType,XbbRefTypeEnum.COMPETITOR.getCode()) && (Objects.equals(attr, CompetitorEnum.VISBLE_DEPT.getAttr()) || Objects.equals(attr,CompetitorEnum.VISBLE_USER.getAttr()));
        //兼容客户线索机会阶段的历史数据格式和阶段推进器的数据格式
        boolean stageOldDataSearch = Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) && Objects.equals(CustomerManagementEnum.CUSTOMER_STAGE.getAttr(), condition.getAttr())
                                    || Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode()) && Objects.equals(SalesOpportunityEnum.SALE_STAGE.getAttr(), condition.getAttr())
                                    || Objects.equals(businessType, XbbRefTypeEnum.CLUE.getCode()) && Objects.equals(ClueEnum.CLUE_STAGE.getAttr(), condition.getAttr());
        if (teamSearch){
            // 特殊索引：这里只是拿了下index的type，所以无需更改
            indexTypeEnum = IndexTypeEnum.getChildByParent(XbbRefTypeEnum.transferBusinessType2Index(businessType));
            teamSearch = !Objects.equals(indexTypeEnum.getType(), IndexTypeEnum.UNKNOWN.getType());
        } else if (!Objects.isNull(businessType) && Objects.equals(FieldTypeEnum.COPY_USER.getType(),fieldType)){
            copySearch = true;
            indexTypeEnum = IndexTypeEnum.getCopyChildByParent(businessType);
        } else if (Objects.equals(fieldType,FieldTypeEnum.WORK_ORDER_DATA_TIME_OUT.getType()) || Objects.equals(fieldType,FieldTypeEnum.WORK_ORDER_DATA_TIME_NOT_OUT.getType())){
            workOrderTimeOut = true;
        } else if (Objects.equals(FieldTypeEnum.getFieldTypeEnum(fieldType), FieldTypeEnum.BIRTHDAY)) {
            birthdaySearch = true;
        }
        //工单阶段在data外，且名字不是stage_id,换成nowStageId去ES匹配;预付款和预收款需要，如果fieldType是updateTime时，不能attr置为num
        if (!Objects.equals(fieldType, FieldTypeEnum.WORK_ORDER_STAGE.getType())) {
            if (Objects.equals(XbbRefTypeEnum.PREPAYMENT_BALANCE.getCode(), businessType) && !FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())) {
                condition.setFieldType(FieldTypeEnum.NUM.getType());
            } else if (Objects.equals(XbbRefTypeEnum.PREPAY_BALANCE.getCode(), businessType) && !FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())) {
                condition.setFieldType(FieldTypeEnum.NUM.getType());
            } else if (Objects.equals(XbbRefTypeEnum.KNOWLEDGE_BASE.getCode(), businessType)) {

            } else {
                if(setInData(fieldType)){
                    if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) && (Objects.equals(PaasConstant.PROVINCE, condition.getAttr()) || Objects.equals(PaasConstant.CITY, condition.getAttr())
                            || Objects.equals(PaasConstant.DISTRICT, condition.getAttr()) || Objects.equals(PaasConstant.ADDRESS, condition.getAttr()))) {
                        attr = "data." + CustomerManagementEnum.ADDRESS.getAttr() + StringConstant.POINT + attr;
                    } else {
                        attr = "data." + attr;
                    }
                }
            }
        } else {
            attr = "nowStageId";
        }
        if(StringUtil.isNotEmpty(condition.getSubAttr())) {
            attr = attr + "." + condition.getSubAttr();
        }
        //这里走的系统的图表不确定解析是否会造成影响,所以把方法进行分离
        if (teamSearch){
            BoolQueryBuilder teamQueryBuilder = boolQuery();
            teamQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            conditionTeamUserChoose(boolQueryBuilder,conditionEnum,attr, condition,teamQueryBuilder,indexTypeEnum);
        } else if (copySearch){
            BoolQueryBuilder copyQueryBuilder = boolQuery();
            copyQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            conditionCopyUserChoose(boolQueryBuilder,conditionEnum,attr, condition,copyQueryBuilder,indexTypeEnum);
        } else if (workOrderTimeOut){
            conditionWorkOrderTimeOut(boolQueryBuilder,fieldType);
        } else if (birthdaySearch) {
            List<Object> valueList = condition.getValue();
            int value = (int)valueList.get(0);
            conditionBirthday(value, businessType, boolQueryBuilder);
        } else if (visibleRangeTeamSearch){
            BoolQueryBuilder teamQueryBuilder = boolQuery();
            teamQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            conditionVisibleRangeTeam(boolQueryBuilder,conditionEnum, condition,teamQueryBuilder, businessType);
        } else if (competitorTeamSearch){
            BoolQueryBuilder teamQueryBuilder = boolQuery();
            teamQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            conditionCompetitorTeam(boolQueryBuilder,conditionEnum, condition,teamQueryBuilder);
        } else if (productWarehouseSearch){
            conditionProductSearch(boolQueryBuilder,conditionEnum, condition);
        //客户机会线索阶段历史数据fieldType可能为3，暂时用attr兼容一下
        } else if (Objects.equals(FieldTypeEnum.STAGE_THRUSTER.getType(), fieldType ) || stageOldDataSearch) {
            conditionStageSearch(boolQueryBuilder, conditionEnum, condition);
        } else if (knowledge) {
            ConditionsEntityExt tempCondition = new ConditionsEntityExt();
            BeanUtil.copyProperties(condition, tempCondition);
            tempCondition.setAttr(attr);
            conditionKnowledgeSearch(boolQueryBuilder, conditionEnum, condition);
        } else {
            ConditionsEntityExt tempCondition = new ConditionsEntityExt();
            BeanUtil.copyProperties(condition, tempCondition);
            tempCondition.setAttr(attr);
            commonConditionSymbolChoose(boolQueryBuilder,conditionEnum,tempCondition);
        }
    }

    /**
     * Description: 子表单查询封装
     * @param boolQueryBuilder
	 * @param condition
	 * @param businessType
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2023/3/20 20:32
     * @since
     */
    private static void parseSubFormBaseCondition(BoolQueryBuilder boolQueryBuilder, ConditionsEntityExt condition, Integer businessType) throws XbbException {
        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
        if (Objects.isNull(conditionEnum)) {
            return;
        }
        if (emptyCheck(condition)) {
            return;
        }

        if (Objects.nonNull(condition) && Objects.nonNull(condition.getAttr()) && !condition.getAttr().contains(FieldTypeEnum.SUB_FORM.getEsalias()) || EsHelper.isSpecialSubForm(condition.getAttr(), businessType)) {
            return;
        }
        String attr = condition.getAttr();
        boolQueryBuilder.filter(termQuery("attr.keyword", attr));

        String subAttr = condition.getSubAttr();
        subAttr = "data." + subAttr;
        condition.setAttr(subAttr);
        condition.setSubAttr(null);
        commonConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);

    }

    /**
     * 知识库字段Es检索
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param condition
     */
    private static void conditionKnowledgeSearch(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        //attr = addKeyWord(condition, attr);
        if (attr.equals("dataId")){

        }else {
            boolQueryBuilder.filter(termQuery(attr,condition.getValue().get(0)));
        }
    }

    /**
     * 阶段推进器字段Es检索
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param condition
     */
    private static void conditionStageSearch(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        List stageValue = condition.getValue();
        switch (conditionEnum){
            case EQUAL :
                boolQueryBuilder.filter(termQuery("data." + attr + ".keyword", String.valueOf(stageValue.get(BasicConstant.ZERO))));
                break;
            case NOEQUAL:
                boolQueryBuilder.mustNot(termQuery("data." + attr + ".keyword", String.valueOf(stageValue.get(BasicConstant.ZERO))));
                break;
            case EMPTY:
                BoolQueryBuilder emptyBool = new BoolQueryBuilder();
                emptyBool.should(boolQuery().mustNot(existsQuery("data." + attr + ".keyword")));
                emptyBool.should(termQuery("data." + attr + ".keyword", ""));
                emptyBool.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.filter(emptyBool);
                break;
            case NOEMPTY:
                boolQueryBuilder.filter(existsQuery("data." + attr + ".keyword"));
                boolQueryBuilder.mustNot(termQuery("data." + attr + ".keyword", ""));
                break;
            case IN:
                BoolQueryBuilder inBool = new BoolQueryBuilder();
                for (int i = 0; i <stageValue.size() ; i++) {
                    inBool.should(termQuery("data." + attr + ".keyword", String.valueOf(stageValue.get(i))));
                }
                inBool.minimumShouldMatch(1);
                boolQueryBuilder.filter(inBool);
                break;
            case NOIN:
                BoolQueryBuilder noInBool = new BoolQueryBuilder();
                for (int i = 0; i <stageValue.size() ; i++) {
                    noInBool.mustNot(termQuery("data." + attr + ".keyword", String.valueOf(stageValue.get(i))));
                }
                boolQueryBuilder.filter(noInBool);
                break;
            default:
                break;
        }
    }

    /**
     * 处理paas表单团队的处理逻辑
     *
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param attr
     * @param condition
     * @param indexTypeEnum
     */
    private static void conditionPaasTeamUserChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, String attr, ConditionsEntityExt condition, BoolQueryBuilder teamQueryBuilder, IndexTypeEnum indexTypeEnum) {
        attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "coUserId");;
        teamQueryBuilder.filter(termQuery(StringConstant.DEL, BasicConstant.ZERO));
        teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(indexTypeEnum.getType(), teamQueryBuilder, ScoreMode.Max);
        boolQueryBuilder.should(hasChildQueryBuilder);
        //负责人
        BoolQueryBuilder ownerBoolQuery= boolQuery();
        ownerBoolQuery.filter(termsQuery(FieldTypeEnum.OWNERID.getAlias() + ".keyword", condition.getValue()));
        boolQueryBuilder.should(ownerBoolQuery);
        boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
    }

    private static void conditionProductSearch(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        BoolQueryBuilder childBuilder = boolQuery();
        switch (conditionEnum){
            case IN:
                childBuilder.filter(termsQuery(condition.getAttr(),condition.getValue()));
                break;
            default:
                return;
        }
        childBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE.getType(),childBuilder, ScoreMode.Max);
        boolQueryBuilder.filter(hasChildQueryBuilder);
    }

    /**
     * 获取拼接的hasChildQueryBuilder
     * @param formDataListDTO
     * @return
     * 创建时间 2020/10/19 11:09 AM
     * 修改时间 2020/10/19 11:09 AM
     * @author chy
     */
    public static HasChildQueryBuilder teamQueryBuilder(FormDataListDTO formDataListDTO) {
        BoolQueryBuilder subFormQueryBuilder = new BoolQueryBuilder();
        List<ConditionsEntityExt> conditions = formDataListDTO.getConditions();
        boolean hasSubFormQuery = false;
        for (ConditionsEntityExt condition : conditions) {
            String subAttr = condition.getSubAttr();
            String attr = condition.getAttr();
            if (StringUtil.isEmpty(subAttr) || EsHelper.isSpecialSubForm(attr, formDataListDTO.getBusinessType())) {
                continue;
            }
            ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
            if (Objects.isNull(conditionEnum)) {
                continue;
            }
            ConditionsEntityExt subFormCondition = new ConditionsEntityExt();
            BeanUtil.copyProperties(condition, subFormCondition);
            if(setInData(condition.getFieldType())){
                subAttr = "data." + subAttr;
            }
            subFormCondition.setAttr(subAttr);
            subFormCondition.setSubAttr("");
            EsUtil.commonConditionSymbolChoose(subFormQueryBuilder, conditionEnum, subFormCondition);
            hasSubFormQuery = true;
        }
        if (hasSubFormQuery) {
            HasChildQueryBuilder  hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SUB_FORM_DATA.getType(),subFormQueryBuilder, ScoreMode.Max);
            return hasChildQueryBuilder;
        }
        return null;
    }

    /**
     * 可见范围转化的协同团队（产品、服务项目）
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param condition
     * @param teamQueryBuilder
     * @param businessType
     */
    private static void conditionVisibleRangeTeam(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition, BoolQueryBuilder teamQueryBuilder, Integer businessType) {
        Integer type = Objects.equals(condition.getAttr(), VisibleRangeEnum.VISIBLE_USER.getAttr()) ? 0 : 1;
        teamQueryBuilder.filter(termQuery(VisibleRangeTeamEnum.getEsAttr(VisibleRangeTeamEnum.TYPE), type));
        teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));

        String teamType = null;
        if (Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())) {
            teamType = IndexTypeEnum.IDX_SAAS_PRODUCT_TEAM.getType();
        } else if(Objects.equals(businessType, XbbRefTypeEnum.SERVICE_PROJECT.getCode())){
            teamType = IndexTypeEnum.IDX_SERVICE_PROJECT_TEAM.getType();
        }
        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(teamType, teamQueryBuilder, ScoreMode.Max);


        String attr = VisibleRangeTeamEnum.getEsAttr(VisibleRangeTeamEnum.RELATION_ID);
        switch (conditionEnum) {
            case EQUAL:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOEQUAL:
                teamQueryBuilder.mustNot(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case IN:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOIN:
                teamQueryBuilder.filter(boolQuery().mustNot(termsQuery(attr,condition.getValue())));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case INCLUDE:
                for (Object obj : condition.getValue()){
                    teamQueryBuilder.should(termQuery(attr, obj));
                }
                teamQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case ALLINCLUDE:
                BoolQueryBuilder allincludeQueryBuilder = boolQuery();
                for (Object obj : condition.getValue()){
                    BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                    innerBoolQueryBuilder.filter(termQuery(attr,obj));
                    HasChildQueryBuilder allHasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(teamType,innerBoolQueryBuilder, ScoreMode.Max);
                    allincludeQueryBuilder.filter(allHasChildQueryBuilder);
                }
                boolQueryBuilder.filter(allincludeQueryBuilder);
                break;
            case EMPTY:
                teamQueryBuilder.filter(existsQuery(VisibleRangeTeamEnum.getEsAttr(VisibleRangeTeamEnum.DATA_ID)));
                boolQueryBuilder.mustNot(hasChildQueryBuilder);
                break;
            case NOEMPTY:
                teamQueryBuilder.filter(existsQuery(VisibleRangeTeamEnum.getEsAttr(VisibleRangeTeamEnum.DATA_ID)));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            default:
                break;
        }
    }

    private static void conditionCompetitorTeam(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition, BoolQueryBuilder teamQueryBuilder) {
        Integer type = Objects.equals(condition.getAttr(),CompetitorEnum.VISBLE_USER.getAttr()) ? 0 : 1;
        teamQueryBuilder.filter(termQuery(CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.TYPE),type));
        teamQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        HasChildQueryBuilder  hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_COMPETITOR_TEAM.getType(),teamQueryBuilder, ScoreMode.Max);

        String attr = CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.RELATION_ID);
        switch (conditionEnum){
            case EQUAL:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOEQUAL:
                teamQueryBuilder.mustNot(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case IN:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOIN:
                teamQueryBuilder.filter(boolQuery().mustNot(termsQuery(attr,condition.getValue())));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case INCLUDE:
                for (Object obj : condition.getValue()){
                    teamQueryBuilder.should(termQuery(attr, obj));
                }
                teamQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case ALLINCLUDE:
                BoolQueryBuilder allincludeQueryBuilder = boolQuery();
                for (Object obj : condition.getValue()){
                    BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                    innerBoolQueryBuilder.filter(termQuery(attr,obj));
                    HasChildQueryBuilder allHasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_COMPETITOR_TEAM.getType(),innerBoolQueryBuilder, ScoreMode.Max);
                    allincludeQueryBuilder.filter(allHasChildQueryBuilder);
                }
                boolQueryBuilder.filter(allincludeQueryBuilder);
                break;
            case EMPTY:
                teamQueryBuilder.filter(existsQuery(CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.DATA_ID)));
                boolQueryBuilder.mustNot(hasChildQueryBuilder);
                break;
            case NOEMPTY:
                teamQueryBuilder.filter(existsQuery(CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.DATA_ID)));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            default:
                break;
        }
    }


    private static void conditionBatch(ConditionEnum conditionEnum, String attr, Integer fieldType, ConditionsEntityExt condition, BoolQueryBuilder batchQueryBuilder) {
        if (Objects.equals(fieldType,FieldTypeEnum.BATCH_PRODUCE_DATE.getType())){
            conditionGuarantee(batchQueryBuilder,conditionEnum.getSymbol(),condition.getValue());
        }else {
//            switch (conditionEnum){
//                case EQUAL:
//                    batchQueryBuilder.filter(termQuery(attr, condition.getValue().get(0)));
//                    break;
//                case IN:
//                    batchQueryBuilder.filter(termsQuery(attr, condition.getValue()));
//                    break;
//            }
            commonConditionSymbolChoose(batchQueryBuilder,conditionEnum,condition);
        }
//        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.BOMFISH_IDX_SAAS_PRODUCT_STOCK_INFO.getType(),batchQueryBuilder, ScoreMode.Max);
//        boolQueryBuilder.filter(hasChildQueryBuilder);
    }

    public static void conditionGuarantee(BoolQueryBuilder batchQueryBuilder, String symbol, List<Object> valueList) {
        batchQueryBuilder.mustNot(termQuery(ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD),0));
        batchQueryBuilder.mustNot(termQuery(ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE),0));
        batchQueryBuilder.must(existsQuery(ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD)));
        batchQueryBuilder.must(existsQuery(ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE)));
        Number numValue = (Number) valueList.get(0);
        Long value = numValue.longValue();
        Long now = DateTimeUtil.getInt();
        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(symbol);
        switch (conditionEnum){
            case EQUAL:
                //已过期
                Script script = new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value < " + now);
                batchQueryBuilder.filter(scriptQuery(script));
                break;
            case LESSTHAN:
            case LESSEQUAL:
                //多少天内过期(不包括已过期)
                script = new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value <= " + (now + value));
                Script script2 = new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value >= " + now);
                batchQueryBuilder.filter(scriptQuery(script));
                batchQueryBuilder.filter(scriptQuery(script2));
                break;
            case GREATERTHAN:
            case GREATEREQUAL:
                //多少后内过期
                script = new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value >= " + (now + value));
                batchQueryBuilder.filter(scriptQuery(script));
                break;
            case RANGE:
                script = new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value >= " + value);
                Long value2 = (Long) valueList.get(1);
                script2 =new Script("doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.GUARANTEE_PERIOD) + "'].value + doc['" + ProductStockSubFormEnum.getAttrConnectData(ProductStockSubFormEnum.PRODUCE_DATE) + "'].value < " + value2);
                batchQueryBuilder.filter(scriptQuery(script));
                batchQueryBuilder.filter(scriptQuery(script2));
                break;
            default:
                break;
        }
//        if (!Objects.equals(status,0)){
//
//            GuaranteeStatusEnum guaranteeStatusEnum = GuaranteeStatusEnum.getByCode(status);
//            if (Objects.isNull(guaranteeStatusEnum)){
//                return;
//            }
//           switch (guaranteeStatusEnum){
//               case OUT_OF_DATE:
//                   Script script = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value <= " + now);
//                   batchQueryBuilder.filter(scriptQuery(script));
//                   break;
//               case EXPIRE_IN_FIFTEEN:
//                   script = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value > " + now);
//                   Script script2 = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value" + "<= " + (now + 15 * TimeConstant.SECONDS_PER_DAY));
//                   batchQueryBuilder.filter(scriptQuery(script));
//                   batchQueryBuilder.filter(scriptQuery(script2));
//                   break;
//               case EXPIRE_IN_THIRTY:
//                   script = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value > " + (now + 15 * TimeConstant.SECONDS_PER_DAY));
//                   script2 = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value" + "<= " + (now + 30 * TimeConstant.SECONDS_PER_DAY));
//                   batchQueryBuilder.filter(scriptQuery(script));
//                   batchQueryBuilder.filter(scriptQuery(script2));
//                   break;
//               case EXPIRE_IN_SIXTY:
//                   script = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value > " + (now + 30 * TimeConstant.SECONDS_PER_DAY));
//                   script2 = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value" + "<= " + (now + 60 * TimeConstant.SECONDS_PER_DAY));
//                   batchQueryBuilder.filter(scriptQuery(script));
//                   batchQueryBuilder.filter(scriptQuery(script2));
//                   break;
//               case EXPIRE_OVER_SIXTY:
//                   script = new Script("doc['guaranteePeriod'].value + doc['produceDate'].value" + "> " + (now + 60 * TimeConstant.SECONDS_PER_DAY));
//                   batchQueryBuilder.filter(scriptQuery(script));
//                   break;
//           }
//        }
    }


    private static void conditionWarning(Integer fieldType,BoolQueryBuilder warehouseQueryBuilder) {
        Integer warningType = WarningSearchEnum.getWarnType(fieldType);
        packageCheckedWarehouseWarningCondition(warningType,warehouseQueryBuilder);
    }

    private static BoolQueryBuilder packageCheckedWarehouseWarningCondition(Integer warningType, BoolQueryBuilder warehouseQueryBuilder) {
        if (Objects.equals(warningType,1)){
            Script script = new Script("doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM) + "'].value > doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.STOCK_UPPER_LIMIT) + "'].value");
            warehouseQueryBuilder.should(scriptQuery(script));
        }else if (Objects.equals(warningType,2)){
            Script script = new Script("doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM) + "'].value < doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.STOCK_LOWER_LIMIT) + "'].value");
            warehouseQueryBuilder.should(scriptQuery(script));
        }else {
            BoolQueryBuilder limitQueryBuilder = boolQuery();
            Script script = new Script("doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM) + "'].value > doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.STOCK_UPPER_LIMIT) + "'].value");
            Script script2 = new Script("doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM) + "'].value < doc['" + ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.STOCK_LOWER_LIMIT) + "'].value");
            limitQueryBuilder.should(scriptQuery(script));
            limitQueryBuilder.should(scriptQuery(script2));
            limitQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            warehouseQueryBuilder.should(limitQueryBuilder);
        }
        return warehouseQueryBuilder;
//        return JoinQueryBuilders.hasChildQuery(IndexTypeEnum.BOMFISH_IDX_SAAS_PRODUCT_WAREHOUSE.getType(),warehouseQueryBuilder,ScoreMode.Max);
    }

    private static void packageAllWarehouseWarningCondition(Integer warningType, BoolQueryBuilder warehouseQueryBuilder) {
        warehouseQueryBuilder.filter(termQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.IS_NOTIFY),1));
        if (Objects.equals(warningType,1)){
            Script script = new Script("doc['data." + ProductEnum.STOCK.getAttr() + "'].value > doc['data." + ProductEnum.STOCK_UPPER_LIMIT.getAttr() + "'].value");
            warehouseQueryBuilder.filter(scriptQuery(script));
        }else if (Objects.equals(warningType,2)){
            Script script = new Script("doc['data." + ProductEnum.STOCK.getAttr() + "'].value < doc['data." + ProductEnum.STOCK_LOWER_LIMIT.getAttr() + "'].value");
            warehouseQueryBuilder.filter(scriptQuery(script));
        }else {
            BoolQueryBuilder limitQueryBuilder = boolQuery();
            Script script = new Script("doc['data." + ProductEnum.STOCK.getAttr() + "'].value > doc['data." + ProductEnum.STOCK_UPPER_LIMIT.getAttr() + "'].value");
            Script script2 = new Script("doc['data." + ProductEnum.STOCK.getAttr() + "'].value < doc['data." + ProductEnum.STOCK_LOWER_LIMIT.getAttr() + "'].value");
            limitQueryBuilder.should(scriptQuery(script));
            limitQueryBuilder.should(scriptQuery(script2));
            limitQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            warehouseQueryBuilder.filter(limitQueryBuilder);
        }
    }

    private static void conditionStock(ConditionEnum conditionEnum, String attr, ConditionsEntityExt condition, BoolQueryBuilder stockQueryBuilder) {
        commonConditionSymbolChoose(stockQueryBuilder, conditionEnum, condition);
//        switch (conditionEnum){
//            case EQUAL:
//                stockQueryBuilder.filter(termQuery(attr, condition.getValue().get(0)));
//                break;
//            case IN:
//                stockQueryBuilder.filter(termsQuery(attr, condition.getValue()));
//                break;
//        }
//        HasChildQueryBuilder  hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.BOMFISH_IDX_SAAS_PRODUCT_WAREHOUSE.getType(),stockQueryBuilder, ScoreMode.Max);
//        boolQueryBuilder.filter(hasChildQueryBuilder);
    }

    /**
     * 空值校验
     * @param condition
     * @return 是空值
     */
    public static Boolean emptyCheck(ConditionsEntityExt condition) {
        String symbol = condition.getSymbol();
        List<Object> value = condition.getValue();
        Boolean isNotEmpty = Objects.nonNull(value) && !value.isEmpty();
        Boolean isDept = (Objects.equals(condition.getFieldType(), FieldTypeEnum.DEPT.getType()) || Objects.equals(condition.getFieldType(), FieldTypeEnum.DEPARTMENTID.getType()));
        if (isNotEmpty) {
            if (condition.getShouldFlag() != null && condition.getShouldFlag()) {
                return false;
            }
            if (isDept) {
                //可能会有long和int
                boolean flag;
                try {
                    flag = Objects.equals(Long.valueOf(value.get(0).toString()), 1L);
                } catch (Exception e) {
                    return true;
                }
                return flag;
            } else if (Objects.equals(condition.getFieldType(), FieldTypeEnum.DEPT_GROUP.getType())) {
                Integer oneInteger = Integer.valueOf(1);
                Long oneLong = Long.valueOf(1);
                return value.contains(oneInteger) || value.contains(oneLong);
            }
        }
        Boolean isDate = Objects.equals(FieldTypeEnum.DATETIME.getType(), condition.getFieldType())
                || Objects.equals(FieldTypeEnum.ADDTIME.getType(), condition.getFieldType()) ||
                Objects.equals(FieldTypeEnum.UPDATETIME.getType(), condition.getFieldType());
        Boolean isRange = Objects.equals(symbol, ConditionEnum.RANGE.getSymbol()) || Objects.equals(symbol, ConditionEnum.NORANGE.getSymbol());
        if (!isDate && isRange) {
            return value.size() < 2;
        } else if (!Objects.equals(symbol, ConditionEnum.EMPTY.getSymbol()) && !Objects.equals(symbol, ConditionEnum.NOEMPTY.getSymbol())) {
            return value.size() < 1 || Objects.isNull(value.get(0)) || value.get(0).toString().isEmpty();
        }
        return false;
    }

    /**
     * 工单超时
     * @param boolQueryBuilder
     * @param fieldType
     */
    private static void conditionWorkOrderTimeOut(BoolQueryBuilder boolQueryBuilder, Integer fieldType) {
        Boolean isOut = Objects.equals(fieldType, FieldTypeEnum.WORK_ORDER_DATA_TIME_OUT.getType());
        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
        if (isOut) {
            BoolQueryBuilder onGongingBuilder = boolQuery();
            onGongingBuilder.filter(termQuery("status", WorkOrderStatusEnum.ONGOING.getCode()));
            onGongingBuilder.mustNot(termQuery("expectedTime", 0));
            Script script1 = new Script("doc['startTime'].value.toEpochSecond() + doc['expectedTime'].value.toEpochSecond() < " + DateTimeUtil.getInt());
            onGongingBuilder.filter(scriptQuery(script1));
            //当前时间 - 开始时间 > 预计完成时间
            //预计完成时间 + 开始时间 < 当前时间
            BoolQueryBuilder completeBuilder = boolQuery();
            completeBuilder.filter(termQuery("status", WorkOrderStatusEnum.FINISH.getCode()));
            completeBuilder.mustNot(termQuery("expectedTime", 0));
            Script script2 = new Script("doc['actualTime'].value.toEpochSecond() > doc['expectedTime'].value.toEpochSecond()");
            completeBuilder.filter(scriptQuery(script2));
            innerBoolQueryBuilder.should(onGongingBuilder);
            innerBoolQueryBuilder.should(completeBuilder);
        } else {
            BoolQueryBuilder onGongingBuilder = boolQuery();
            onGongingBuilder.filter(termQuery("status", WorkOrderStatusEnum.ONGOING.getCode()));
            Script script1 = new Script("doc['startTime'].value.toEpochSecond() + doc['expectedTime'].value.toEpochSecond() >= " + DateTimeUtil.getInt());
            onGongingBuilder.filter(scriptQuery(script1));
            //当前时间 - 开始时间 < 预计完成时间
            //预计完成时间 + 开始时间 > 当前时间
            BoolQueryBuilder completeBuilder = boolQuery();
            completeBuilder.filter(termQuery("status", WorkOrderStatusEnum.FINISH.getCode()));
            Script script2 = new Script("doc['actualTime'].value.toEpochSecond() <= doc['expectedTime'].value.toEpochSecond()");
            completeBuilder.filter(scriptQuery(script2));
            BoolQueryBuilder unAccpectBuilder = boolQuery();
            unAccpectBuilder.filter(termQuery("status", WorkOrderStatusEnum.UNACCEPTED.getCode()));
            innerBoolQueryBuilder.should(onGongingBuilder);
            innerBoolQueryBuilder.should(unAccpectBuilder);
            innerBoolQueryBuilder.should(completeBuilder);
        }
        boolQueryBuilder.filter(innerBoolQueryBuilder);

    }
    /**
     * 生日筛选条件
     *
     * @param boolQueryBuilder 条件
     * @param value            生日选项
     * @throws
     * @author 徐俊杰
     * @date 2019/6/21 19:19
     * @since v1.0
     */
    public static void conditionBirthdayForContact(BoolQueryBuilder boolQueryBuilder, int value, Integer advanceRemindTime) {
        //生日选项
        BirthdayFilterEnum birthdayFilterEnum = BirthdayFilterEnum.getByValue(value);
        if (birthdayFilterEnum == null) {
            return;
        }
        int solarStartTime;
        BirthdayPojo birthdayPojo = new BirthdayPojo();
        //相关字段
        String birthdayFlag = ContactEnum.getAttrConnectData(ContactEnum.BIRTHDAY_FLAG);
        String birthday = ContactEnum.getEsAttr4Keyword(ContactEnum.BIRTHDAY_MMDD);
        switch (birthdayFilterEnum) {
            case TODAY:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case TOMORROW:
                solarStartTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case SEVEN_DAYS:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 6, birthdayPojo);
                break;
            case REMIND:
                if (advanceRemindTime == null) {
                    break;
                }
                solarStartTime = DateUtil.getTodayInt() + advanceRemindTime * TimeConstant.SECONDS_PER_DAY;
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            default:
                break;
        }
        List<String> solarList = birthdayPojo.getSolarList();
        List<String> lunarList = birthdayPojo.getLunarList();
        //阳历生日查询条件
        BoolQueryBuilder solarCalendarQuery = boolQuery();
        solarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.BIRTHDAY.getValue()));
        solarCalendarQuery.must(termsQuery(birthday, solarList));
        boolQueryBuilder.should(solarCalendarQuery);
        //阴历生日查询条件
        BoolQueryBuilder lunarCalendarQuery = boolQuery();
        lunarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.LUNAR_BIRTHDAY.getValue()));
        lunarCalendarQuery.must(termsQuery(birthday, lunarList));
        boolQueryBuilder.should(lunarCalendarQuery);
        boolQueryBuilder.minimumShouldMatch(EsNormalConstant.MINI_MUM_SHOULD_MATCH);
    }
    /**
     * 生日筛选条件
     *
     * @param boolQueryBuilder 条件
     * @see BirthdayFilterEnum
     * @param value            生日选项
     * @throws
     * @author 徐俊杰
     * @date 2019/6/21 19:19
     * @since v1.0
     */
    public static void conditionBirthday(BoolQueryBuilder boolQueryBuilder, int value, Integer advanceRemindTime) {
        conditionBirthday(boolQueryBuilder, value, advanceRemindTime, null);
    }
    /**
     * 重载com.xbongbong.paas.elasticsearch.util.EsUtil#conditionBirthday(org.elasticsearch.index.query.BoolQueryBuilder, int, java.lang.Integer)
     * @param boolQueryBuilder
     * @see BirthdayFilterEnum
     * @param value 生日选项
     * @param advanceRemindTime
     * @param businessType 业务类型
     * @return void
     * @author 吴峰
     * @date 2022/1/17 17:20
     * @throws XbbException
     */
    public static void conditionBirthday(BoolQueryBuilder boolQueryBuilder, int value, Integer advanceRemindTime, Integer businessType) {
        //生日选项
        BirthdayFilterEnum birthdayFilterEnum = BirthdayFilterEnum.getByValue(value);
        if (birthdayFilterEnum == null) {
            return;
        }
        int solarStartTime;
        BirthdayPojo birthdayPojo = new BirthdayPojo();
        //相关字段
        String birthdayFlag = CustomerManagementEnum.getAttrConnectData(CustomerManagementEnum.BIRTHDAY_FLAG);
        String birthday = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.BIRTHDAY_MMDD);
        if (Objects.nonNull(businessType)) {
            XbbRefTypeEnum refTypeEnum = XbbRefTypeEnum.getByCode(businessType);
            switch (refTypeEnum) {
                case CUSTOMER_MANAGEMENT:
                    birthdayFlag = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.BIRTHDAY_FLAG);
                    birthday = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.BIRTHDAY_MMDD);
                    break;
                case CONTACT:
                    birthdayFlag = ContactEnum.getEsAttr4Keyword(ContactEnum.BIRTHDAY_FLAG);
                    birthday = ContactEnum.getEsAttr4Keyword(ContactEnum.BIRTHDAY_MMDD);
                    break;
                case DISTRIBUTOR_CONTACT:
                    birthdayFlag = DistributorContactEnum.getEsAttr4Keyword(DistributorContactEnum.BIRTHDAY_FLAG);
                    birthday = DistributorContactEnum.getEsAttr4Keyword(DistributorContactEnum.BIRTHDAY_MMDD);
                    break;
                case SUPPLIER_CONTACT:
                    birthdayFlag = SupplierContactEnum.getEsAttr4Keyword(SupplierContactEnum.BIRTHDAY_FLAG);
                    birthday = SupplierContactEnum.getEsAttr4Keyword(SupplierContactEnum.BIRTHDAY_MMDD);
                    break;
                default:
                    break;
            }
        }
        switch (birthdayFilterEnum) {
            case TODAY:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case TOMORROW:
                solarStartTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case SEVEN_DAYS:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 6, birthdayPojo);
                break;
            case REMIND:
                if (advanceRemindTime == null) {
                    break;
                }
                solarStartTime = DateUtil.getTodayInt() + advanceRemindTime * TimeConstant.SECONDS_PER_DAY;
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            default:
                break;
        }
        List<String> solarList = birthdayPojo.getSolarList();
        List<String> lunarList = birthdayPojo.getLunarList();
        //阳历生日查询条件
        BoolQueryBuilder solarCalendarQuery = boolQuery();
        solarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.BIRTHDAY.getValue()));
        solarCalendarQuery.must(termsQuery(birthday, solarList));
        boolQueryBuilder.should(solarCalendarQuery);
        //阴历生日查询条件
        BoolQueryBuilder lunarCalendarQuery = boolQuery();
        lunarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.LUNAR_BIRTHDAY.getValue()));
        lunarCalendarQuery.must(termsQuery(birthday, lunarList));
        boolQueryBuilder.should(lunarCalendarQuery);
        boolQueryBuilder.minimumShouldMatch(EsNormalConstant.MINI_MUM_SHOULD_MATCH);
    }

    /**
     * 生日筛选条件
     *
     * @param boolQueryBuilder 条件
     * @param value            生日选项
    */
    public static void conditionBirthday(int value, Integer businessType, BoolQueryBuilder boolQueryBuilder) {
        //相关字段
        String birthdayFlag = "";
        String birthday = "";
        XbbRefTypeEnum refTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        switch (refTypeEnum) {
            case CUSTOMER_MANAGEMENT:
                birthdayFlag = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.BIRTHDAY_FLAG);
                birthday = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.BIRTHDAY_MMDD);
                break;
            case CONTACT:
                birthdayFlag = ContactEnum.getEsAttr4Keyword(ContactEnum.BIRTHDAY_FLAG);
                birthday = ContactEnum.getEsAttr4Keyword(ContactEnum.BIRTHDAY_MMDD);
                break;
            case DISTRIBUTOR_CONTACT:
                birthdayFlag = DistributorContactEnum.getEsAttr4Keyword(DistributorContactEnum.BIRTHDAY_FLAG);
                birthday = DistributorContactEnum.getEsAttr4Keyword(DistributorContactEnum.BIRTHDAY_MMDD);
                break;
            case SUPPLIER_CONTACT:
                birthdayFlag = SupplierContactEnum.getEsAttr4Keyword(SupplierContactEnum.BIRTHDAY_FLAG);
                birthday = SupplierContactEnum.getEsAttr4Keyword(SupplierContactEnum.BIRTHDAY_MMDD);
                break;
            default:
                break;
        }
        if (StringUtil.isEmpty(birthday)) {
            return;
        }
        int solarStartTime;
        BirthdayPojo birthdayPojo = new BirthdayPojo();
        //生日选项
        BirthdayFilterEnum birthdayFilterEnum = BirthdayFilterEnum.getByValue(value);
        if (birthdayFilterEnum == null) {
            return;
        }
        switch (birthdayFilterEnum) {
            case TODAY:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case TOMORROW:
                solarStartTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                getBirthdayTime(solarStartTime, 1, birthdayPojo);
                break;
            case SEVEN_DAYS:
                solarStartTime = DateUtil.getTodayInt();
                getBirthdayTime(solarStartTime, 6, birthdayPojo);
                break;
            default:
                break;
        }
        List<String> solarList = birthdayPojo.getSolarList();
        List<String> lunarList = birthdayPojo.getLunarList();
        //阳历生日查询条件
        BoolQueryBuilder solarCalendarQuery = boolQuery();
        solarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.BIRTHDAY.getValue()));
        solarCalendarQuery.must(termsQuery(birthday, solarList));
        boolQueryBuilder.should(solarCalendarQuery);
        //阴历生日查询条件
        BoolQueryBuilder lunarCalendarQuery = boolQuery();
        lunarCalendarQuery.must(termQuery(birthdayFlag, BirthdayTypeEnum.LUNAR_BIRTHDAY.getValue()));
        lunarCalendarQuery.must(termsQuery(birthday, lunarList));
        boolQueryBuilder.should(lunarCalendarQuery);
        boolQueryBuilder.minimumShouldMatch(EsNormalConstant.MINI_MUM_SHOULD_MATCH);
    }

    /**
     * 抄送人子文档拼装
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param attr
     * @param condition
     * @param copyQueryBuilder
     * @param indexTypeEnum
     */
    private static void conditionCopyUserChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, String attr, ConditionsEntityExt condition, BoolQueryBuilder copyQueryBuilder, IndexTypeEnum indexTypeEnum) {
        attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "userId");
        switch (conditionEnum){
            case EQUAL:
                copyQueryBuilder.filter(termQuery(attr, condition.getValue().get(0)));
                break;
            default:
                break;
        }
        HasChildQueryBuilder  hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(indexTypeEnum.getType(),copyQueryBuilder, ScoreMode.Max);
        boolQueryBuilder.filter(hasChildQueryBuilder);
    }

    /**
     * 协同团队子文档拼装
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param attr
     * @param condition
     * @param teamQueryBuilder
     * @param indexTypeEnum
     */
    private static void conditionTeamUserChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, String attr, ConditionsEntityExt condition, BoolQueryBuilder teamQueryBuilder, IndexTypeEnum indexTypeEnum) {
        Integer isMain = null;
        Integer del = 0;
        if (Objects.equals(attr, FieldTypeEnum.TEAM_USER.getAlias())) {
            attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "userId");
            teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        }
        if (Objects.equals(indexTypeEnum, IndexTypeEnum.IDX_SAAS_PRODUCT_TEAM)
                || Objects.equals(indexTypeEnum, IndexTypeEnum.IDX_SERVICE_PROJECT_TEAM)) {
            if (Objects.equals(attr, FieldTypeEnum.OWNERID.getAlias())) {
                attr = VisibleRangeTeamEnum.getEsAttr(VisibleRangeTeamEnum.RELATION_ID);
                teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                if (Objects.nonNull(condition.getTeamType())) {
                    teamQueryBuilder.filter(termQuery(ProductTeamEnum.getEsAttr(ProductTeamEnum.TYPE), condition.getTeamType()));
                }
            }
        } else if (Objects.equals(indexTypeEnum,IndexTypeEnum.IDX_SAAS_COMPETITOR_TEAM)){
            if (Objects.equals(attr, FieldTypeEnum.OWNERID.getAlias())) {
                attr = CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.RELATION_ID);
                teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                if (Objects.nonNull(condition.getTeamType())) {
                    teamQueryBuilder.filter(termQuery(CompetitorTeamEnum.getEsAttr(CompetitorTeamEnum.TYPE), condition.getTeamType()));
                }
            }
        }else {
            if (Objects.equals(attr, FieldTypeEnum.OWNERID.getAlias())) {
                attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "userId");
                isMain = 1;
                del = 0;
            } else if (Objects.equals(attr, FieldTypeEnum.COUSERID.getAlias())) {
                attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "userId");
                isMain = 0;
                del = 0;
            } else if (Objects.equals(attr, FieldTypeEnum.PRE_OWNER_ID.getAlias())) {
                attr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "userId");
                isMain = 1;
                del = -1;
            }
            if (Objects.nonNull(isMain)) {
                teamQueryBuilder.filter(termQuery(SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "isMain"), isMain));
            }

            teamQueryBuilder.filter(termQuery(StringConstant.DEL, del));
        }
        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(indexTypeEnum.getType(), teamQueryBuilder, ScoreMode.Max);
        switch (conditionEnum) {
            case EQUAL:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOEQUAL:
                teamQueryBuilder.mustNot(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case IN:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case NOIN:
                teamQueryBuilder.filter(boolQuery().mustNot(termsQuery(attr, condition.getValue())));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case INCLUDE:
                teamQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                boolQueryBuilder.filter(hasChildQueryBuilder);
                break;
            case ALLINCLUDE:
                BoolQueryBuilder allincludeQueryBuilder = boolQuery();
                for (Object obj : condition.getValue()) {
                    BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                    innerBoolQueryBuilder.filter(termQuery(attr, obj));
                    if (Objects.nonNull(isMain)) {
                        innerBoolQueryBuilder.filter(termQuery(SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, "isMain"), isMain));
                    }
                    innerBoolQueryBuilder.filter(termQuery(StringConstant.DEL, del));
                    HasChildQueryBuilder allHasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(indexTypeEnum.getType(), innerBoolQueryBuilder, ScoreMode.Max);
                    allincludeQueryBuilder.filter(allHasChildQueryBuilder);
                }
                boolQueryBuilder.filter(allincludeQueryBuilder);
                break;
            default:
                break;
        }

    }


    /**
     * 解析筛选条件或查询条件
     * @param boolQueryBuilder 查询条件
     * @param conditionJson 筛选条件 或 查询条件
     * @param isSingle 是否为单表
     * @param isFilterCondition 是否是筛选
     * @throws XbbException error
     */
    public static void parseFilterOrSearchCondition(BoolQueryBuilder boolQueryBuilder, JSONArray conditionJson, boolean isSingle, boolean isFilterCondition,
                                                    Map<Integer, Boolean> sourcesMap, boolean isPublicFlag) throws XbbException {
        if (conditionJson.size() > 0) {
            for (Object o : conditionJson) {
                JSONObject filterJson = (JSONObject) o;
                ConditionsEntityExt condition = JSONObject.parseObject(filterJson.toJSONString(), ConditionsEntityExt.class);
                String parentAttr = filterJson.getString("parentAttr");
                if (parentAttr != null && !Objects.equals(parentAttr, "")) {
                    JSONObject parentObj = filterJson.getJSONObject("parentSubFormAttr");
                    Integer parentFieldType = parentObj == null ? null : parentObj.getInteger("fieldType");
                    if (!Objects.equals(parentFieldType, FieldTypeEnum.CONTACT_NUMBER.getType())) {
                        condition.setSubAttr(parentAttr);
                    }
                }
                boolean emptyFlag = Objects.equals(condition.getSymbol(), ConditionEnum.EMPTY.getSymbol()) || Objects.equals(condition.getSymbol(), ConditionEnum.NOEMPTY.getSymbol());
                //如果value值为空则跳过
                if (!emptyFlag && (Objects.isNull(condition.getValue()) || condition.getValue().isEmpty())) {
                    continue;
                }
                if (!emptyFlag && (condition.getValue() == null || condition.getValue().get(0) == null ||"".equals(condition.getValue().get(0)))) {
                    continue;
                }
                Long formId = filterJson.getLong("formId");
                boolean isTeam = sourcesMap.get(formId.intValue());

                Integer fieldType = condition.getFieldType();
                String attr = setInData(fieldType) && isSingle ? "data." + condition.getAttr() : condition.getAttr();
                condition.setAttr(attr);
                ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
                conditionSymbolChoose(boolQueryBuilder, conditionEnum, condition, isTeam, isPublicFlag, isSingle, filterJson.getInteger("businessType"));
            }
        }

    }

    /**
     * 使用script实现多字段聚合
     * @param sourceBuilder
     * @param groupAttrList
     * @param summaryAttrList
     * @param chartEntity
     */
    public static void scriptAggregation(SearchSourceBuilder sourceBuilder, List<FieldAttrPojo> groupAttrList, List<FieldAttrPojo> summaryAttrList, Map<String, FieldAttrPojo> summaryAttrMap, ChartEntity chartEntity, Map<Integer, FieldAttrPojo> timeIndexMapping) throws XbbException {
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        boolean isSingle = !Objects.equals(chartEntity.getMuti(), BasicConstant.ZERO);
        //封装行列表头查询
        String scriptStr = getScriptObj(groupAttrList, isSingle, timeIndexMapping, chartEntity);
        TermsAggregationBuilder scriptAggs = AggregationBuilders.terms("summary_script").script(new Script(scriptStr)).size(SizeConstant.TERM_AGG_MAX_BUCKETS);
        for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
            StringBuilder field = new StringBuilder();
            StringBuilder aggName = new StringBuilder();
            String formId = fieldAttrPojo.getFormId().toString();
            String attr = getAggNameAndField(fieldAttrPojo, isSingle, field, aggName);
            String fieldResult = field.toString();
            if (attr.contains("count")) {
                fieldResult = "id";
                if(formIdAttr != null && formIdAttr.size() > 0){
                    fieldResult = formIdAttr.getJSONObject(formId).getString(StringConstant.DATA_ID);
                    aggName = new StringBuilder(formId).append(aggName);
                }
                AggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName.toString()).field(fieldResult);
                scriptAggs.subAggregation(countAggregationBuilder);
                summaryAttrMap.put(aggName.toString(), fieldAttrPojo);
                continue;
            }
            summaryAttrMap.put(aggName.toString(), fieldAttrPojo);
            SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(aggName.toString()).field(fieldResult);
            scriptAggs.subAggregation(sumAggregationBuilder);
        }
        sourceBuilder.aggregation(scriptAggs).size(0);

    }

    /**
     * 获取脚本的source
     * @param groupAttrList
     * @return java.lang.String
     */
    private static String getScriptObj(List<FieldAttrPojo> groupAttrList, boolean isSingle, Map<Integer, FieldAttrPojo> timeIndexMapping, ChartEntity chartEntity) throws XbbException {
        StringBuilder sb = new StringBuilder();
        String docStr = "doc['%s'].values+'&&'+";
        StringBuilder field;
        StringBuilder aggName = new StringBuilder();
        for (int i = 0; i < groupAttrList.size(); i++) {
            FieldAttrPojo attrPojo = groupAttrList.get(i);
            if (EsHelper.isDateTimeByFieldType(attrPojo.getFieldType())) {
                timeIndexMapping.put(i, attrPojo);
            } else if (EsHelper.isTeamLogicByFieldType(attrPojo.getFieldType(), attrPojo.getBusinessType()) && !isSingle) {
                //多表团队处理
                String teamField = "myTeamMain_" + getTeamIdx(chartEntity, attrPojo.getFormId()) + ".userId";
                attrPojo.setAttr(teamField);
            }
            field = new StringBuilder();
            getAggNameAndField(attrPojo, isSingle, field, aggName);
            sb.append(String.format(docStr, field));
        }

        return sb.substring(0,sb.length()-6);
    }

    /**
         * 自定义图表三层聚合,三层分组第四层统计
         */
    public static void statisticTableAggregation(SearchSourceBuilder sourceBuilder, List<FieldAttrPojo> groupAttrList, List<FieldAttrPojo> summaryAttrList,
                                                 Map<String, String> sortMap, ChartEntity chartEntity) throws XbbException {
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        boolean isSingle = getSingle(chartEntity);
        boolean isYearChain = isYearChain(chartEntity);
        ValuesSourceAggregationBuilder termsAggregationBuilder = null;
        ValuesSourceAggregationBuilder tempAggregationBuilder = null;
        if (CollectionsUtil.isNotEmpty(groupAttrList)) {
            for (int i = 0; i < groupAttrList.size(); i++) {
                StringBuilder field = new StringBuilder();
                StringBuilder aggName = new StringBuilder();
                FieldAttrPojo fieldAttrPojo = groupAttrList.get(i);
                getAggNameAndField(fieldAttrPojo, isSingle, field, aggName);
                Boolean asc = null;
                if (sortMap != null) {
                    String ascStr = sortMap.get(aggName.toString());
                    asc = ascStr == null ? null : Objects.equals(ascStr, StringConstant.SORT_ASC_TAG);
                }
                if (i == 0) {
                    if (EsHelper.isDateTimeByFieldType(fieldAttrPojo.getFieldType())) {
                        termsAggregationBuilder = esHelper.getBiDateHistogramAggregation(aggName.toString(), field.toString(), fieldAttrPojo.getDateGroupType(), asc, isYearChain);
                        tempAggregationBuilder = termsAggregationBuilder;
                    } else if (EsHelper.isTeamLogicByFieldType(fieldAttrPojo.getFieldType(), fieldAttrPojo.getBusinessType())){
                        if (!isSingle) {
                            String teamField = "myTeamMain_" + getTeamIdx(chartEntity, fieldAttrPojo.getFormId()) + ".userId.keyword";
                            TermsAggregationBuilder termAgg = AggregationBuilders.terms(aggName.toString()).field(teamField);
                            termAgg.executionHint(ElasticConstant.EXECUTION_HINT);
                            termsAggregationBuilder = termAgg.size(SizeConstant.TERM_AGG_MAX_BUCKETS);
                            tempAggregationBuilder = termsAggregationBuilder;
                        } else {
                            // 特殊索引：这里只是拿了下index的type，所以无需更改
                            //TODO 单表负责人分组，若存在多个分组条件，且负责人字段非最后一个条件时，分组聚合不可用，以下代码存在问题
                            String teamType = IndexTypeEnum.getChildByParent(fieldAttrPojo.getBusinessType()).getType();
                            ChildrenAggregationBuilder childrenAgg = JoinAggregationBuilders.children(aggName.toString(), teamType);
                            TermsAggregationBuilder subAgg = AggregationBuilders.terms(aggName.toString()).field("userId.keyword");
                            subAgg.executionHint(ElasticConstant.EXECUTION_HINT);
                            termsAggregationBuilder = childrenAgg.subAggregation(subAgg);
                            tempAggregationBuilder = subAgg;
                        }
                    } else {
                        TermsAggregationBuilder builder = AggregationBuilders.terms(aggName.toString()).field(field.toString()).size(SizeConstant.TERM_AGG_MAX_BUCKETS);
                        builder.executionHint(ElasticConstant.EXECUTION_HINT);
                        if (asc != null) {
                            builder.order(BucketOrder.key(asc));
                        }
                        termsAggregationBuilder = builder;
                        tempAggregationBuilder = termsAggregationBuilder;
                    }
                } else {
                    ValuesSourceAggregationBuilder subAggregationBuilder;
                    if (EsHelper.isDateTimeByFieldType(fieldAttrPojo.getFieldType())) {
                        subAggregationBuilder = esHelper.getBiDateHistogramAggregation(aggName.toString(), field.toString(), fieldAttrPojo.getDateGroupType(), asc, isYearChain);
                    } else if (EsHelper.isTeamLogicByFieldType(fieldAttrPojo.getFieldType(), fieldAttrPojo.getBusinessType())){
                        if (!isSingle) {
                            String teamField = "myTeamMain_" + getTeamIdx(chartEntity, fieldAttrPojo.getFormId()) + ".userId.keyword";
                            TermsAggregationBuilder termAgg = AggregationBuilders.terms(aggName.toString()).field(teamField);
                            termAgg.executionHint(ElasticConstant.EXECUTION_HINT);
                            subAggregationBuilder = termAgg.size(SizeConstant.TERM_AGG_MAX_BUCKETS);
                        } else {
                            // 特殊索引：这里只是拿了下index的type，所以无需更改
                            //TODO 单表负责人分组，若存在多个分组条件，且负责人字段非最后一个条件时，分组聚合不可用，以下代码存在问题
                            String teamType = IndexTypeEnum.getChildByParent(fieldAttrPojo.getBusinessType()).getType();
                            ChildrenAggregationBuilder childrenAgg = JoinAggregationBuilders.children(aggName.toString(), teamType);
                            TermsAggregationBuilder subAgg = AggregationBuilders.terms(aggName.toString()).field("userId.keyword");
                            subAgg.executionHint(ElasticConstant.EXECUTION_HINT);
                            subAggregationBuilder = childrenAgg.subAggregation(subAgg);
                        }
                    } else {
                        TermsAggregationBuilder builder = AggregationBuilders.terms(aggName.toString()).field(field.toString()).size(SizeConstant.TERM_AGG_MAX_BUCKETS);
                        builder.executionHint(ElasticConstant.EXECUTION_HINT);
                        if (asc != null) {
                            builder.order(BucketOrder.key(asc));
                        }
                        subAggregationBuilder = builder;
                    }
                    tempAggregationBuilder.subAggregation(subAggregationBuilder);
                    tempAggregationBuilder = subAggregationBuilder;
                }
                if (i == groupAttrList.size() - 1) {
                    if (sortMap != null && !sortMap.isEmpty()) {
                        esSortStatisticsByFiled(tempAggregationBuilder, sortMap, summaryAttrList, chartEntity);
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(summaryAttrList)) {
                for (int i = 0; i < summaryAttrList.size(); i++) {
                    FieldAttrPojo fieldAttrPojo = summaryAttrList.get(i);
                    StringBuilder field = new StringBuilder();
                    StringBuilder aggName = new StringBuilder();
                    String formId = fieldAttrPojo.getFormId().toString();
                    String attr = getAggNameAndField(fieldAttrPojo, isSingle, field, aggName);
                    String fieldResult = field.toString();
                    if (attr.contains("count")) {
                        fieldResult = "id";
                        if(formIdAttr != null && formIdAttr.size() > 0){
                            fieldResult = formIdAttr.getJSONObject(formId).getString(StringConstant.DATA_ID);
                            aggName = new StringBuilder(formId).append(aggName);
                        }
                        // 放开汇总字段可重复
                        aggName.append("&").append(fieldAttrPojo.getGroupIndex());
                        AggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName.toString()).field(fieldResult);
                        tempAggregationBuilder.subAggregation(countAggregationBuilder);
                        continue;
                    }
                    // 放开汇总字段可重复
                    aggName.append("&").append(fieldAttrPojo.getGroupIndex());
                    //汇总字段是计算字段
                    if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldAttrPojo.getFieldType())) {
                        List<String> fieldsList = new ArrayList<>();
                        //判断单表还是多表，拼script
                        JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                        String formula = formulaInfo.getString("formula");
                        //公式转换
                        try {
                            formula = getString(sourceBuilder, formIdAttr, isSingle, fieldsList, formulaInfo, formula, formId);
                        } catch (XbbException e) {
                            LOG.error("计算字段的公式格式有问题", e);
                            throw e;
                        }
                        String aggType = fieldAttrPojo.getAggType();
                        AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                        switch (aggTypeEnum) {
                            case SUM:
                                SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(aggName.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(sumAggregationBuilder);
                                break;
                            case AVG:
                                AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(aggName.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(avgAggregationBuilder);
                                break;
                            case MAX:
                                MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(aggName.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(maxAggregationBuilder);
                                break;
                            case MIN:
                                MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(aggName.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(minAggregationBuilder);
                                break;
                            case COUNT:
                                ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(countAggregationBuilder);
                                break;
                        }
                    } else {
                        String aggType = fieldAttrPojo.getAggType();
                        AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                        switch (aggTypeEnum) {
                            case AVG:
                                AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(aggName.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(avgAggregationBuilder);
                                break;
                            case MAX:
                                MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(aggName.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(maxAggregationBuilder);
                                break;
                            case MIN:
                                MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(aggName.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(minAggregationBuilder);
                                break;
                            case COUNT:
                                ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(countAggregationBuilder);
                                break;
                            default:
                                SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(aggName.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(sumAggregationBuilder);
                                break;
                        }
                    }
                }
            }
            sourceBuilder.aggregation(termsAggregationBuilder);
        }
        sourceBuilder.size(0);
    }

    /**
     * @Description 自定义图表三层聚合,三层分组第四层统计(指标图)(指标图只有单表)
     * @param sourceBuilder, groupAttrList, summaryAttrList, sortMap, chartEntity
     * @return void
     * @author weiming
     * @Date  13:42
     **/
    public static void targetChartAggregation(SearchSourceBuilder sourceBuilder, List<FieldAttrPojo> groupAttrList, List<FieldAttrPojo> summaryAttrList,
                                                 Map<String, String> sortMap, ChartEntity chartEntity) throws XbbException {
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        boolean isSingle = getSingle(chartEntity);
        boolean isYearChain = isYearChain(chartEntity);
        TermsAggregationBuilder termsAggregationBuilder = null;
        ValuesSourceAggregationBuilder tempAggregationBuilder = null;
        StringBuilder aggName1 = new StringBuilder();
        StringBuilder aggName2 = new StringBuilder();
        if (CollectionsUtil.isNotEmpty(groupAttrList)) {
            for (int i = 0; i < groupAttrList.size(); i++) {
                StringBuilder field = new StringBuilder();
                FieldAttrPojo fieldAttrPojo = groupAttrList.get(i);
                getAggNameAndField(fieldAttrPojo, isSingle, field, aggName1);
                Boolean asc = null;
                if (sortMap != null) {
                    String ascStr = sortMap.get(aggName1.toString());
                    asc = ascStr == null ? null : Objects.equals(ascStr, StringConstant.SORT_ASC_TAG);
                }
                if (i == 0) {
                    if (EsHelper.isDateTimeByFieldType(fieldAttrPojo.getFieldType())) {
                        tempAggregationBuilder = esHelper.getBiDateHistogramAggregation(aggName1.toString(), field.toString(), fieldAttrPojo.getDateGroupType(), asc, isYearChain);
                    } else if (EsHelper.isTeamLogicByFieldType(fieldAttrPojo.getFieldType(), fieldAttrPojo.getBusinessType())){
                        //TODO 单表负责人分组，若存在多个分组条件，且负责人字段非最后一个条件时，分组聚合不可用，以下代码存在问题
                        String teamField = "myTeamMain_" + getTeamIdx(chartEntity, fieldAttrPojo.getFormId()) + ".userId.keyword";
                        termsAggregationBuilder = AggregationBuilders.terms(aggName1.toString()).field(teamField).size(ChartConstant.CHART_AGG_SIZE);
                        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
                        tempAggregationBuilder = termsAggregationBuilder;
                    } else {
                        termsAggregationBuilder = AggregationBuilders.terms(aggName1.toString()).field(field.toString()).size(ChartConstant.CHART_AGG_SIZE);
                        if (asc != null) {
                            termsAggregationBuilder.order(BucketOrder.key(asc));
                        }
                        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
                        tempAggregationBuilder = termsAggregationBuilder;
                    }
                    if (sortMap != null && !sortMap.isEmpty()) {
                        esSortStatisticsByFiled(tempAggregationBuilder, sortMap, summaryAttrList, chartEntity);
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(summaryAttrList)) {
                for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
                    StringBuilder field = new StringBuilder();
                    String formId = fieldAttrPojo.getFormId().toString();
                    String attr = getAggNameAndField(fieldAttrPojo, isSingle, field, aggName2);
                    String fieldResult = field.toString();
                    if (attr.contains("count")) {
                        fieldResult = "id";
                        if (formIdAttr != null && formIdAttr.size() > 0) {
                            fieldResult = formIdAttr.getJSONObject(formId).getString(StringConstant.DATA_ID);
                            aggName2 = new StringBuilder(formId).append(aggName2);
                        }
                        AggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName2.toString()).field(fieldResult);
                        tempAggregationBuilder.subAggregation(countAggregationBuilder);
                        continue;
                    }
                    String aggType = fieldAttrPojo.getAggType();
                    AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                    //如果是计算字段
                    if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),fieldAttrPojo.getFieldType())) {
                        List<String> fieldsList = new ArrayList<>();
                        //判断单表还是多表，拼script
                        JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                        String formula = formulaInfo.getString("formula");
                        try {
                            formula = getString(sourceBuilder, chartEntity.getFormIdAttr(), true, fieldsList, formulaInfo, formula, formId);
                        } catch (XbbException e) {
                            LOG.error("计算字段的公式格式有问题", e);
                            throw e;
                        }
                        switch (aggTypeEnum) {
                            case SUM:
                                SumAggregationBuilder sumScriptAggregationBuilder = AggregationBuilders.sum(aggName2.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(sumScriptAggregationBuilder);
                                break;
                            case AVG:
                                AvgAggregationBuilder avgScriptAggregationBuilder = AggregationBuilders.avg(aggName2.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(avgScriptAggregationBuilder);
                                break;
                            case MAX:
                                MaxAggregationBuilder maxScriptAggregationBuilder = AggregationBuilders.max(aggName2.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(maxScriptAggregationBuilder);
                                break;
                            case MIN:
                                MinAggregationBuilder minScriptAggregationBuilder = AggregationBuilders.min(aggName2.toString()).script(new Script(formula));
                                tempAggregationBuilder.subAggregation(minScriptAggregationBuilder);
                                break;
                        }
                    }else{
                        switch (aggTypeEnum) {
                            case SUM:
                                SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(aggName2.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(sumAggregationBuilder);
                                break;
                            case AVG:
                                AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(aggName2.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(avgAggregationBuilder);
                                break;
                            case MAX:
                                MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(aggName2.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(maxAggregationBuilder);
                                break;
                            case MIN:
                                MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(aggName2.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(minAggregationBuilder);
                                break;
                            case COUNT:
                                AggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName2.toString()).field(fieldResult);
                                tempAggregationBuilder.subAggregation(countAggregationBuilder);
                                break;
                        }
                    }
                }
            }
            sourceBuilder.aggregation(tempAggregationBuilder);
            //累加所有桶的值
            SumBucketPipelineAggregationBuilder sumBucket = new SumBucketPipelineAggregationBuilder("sum", aggName1.append('>').append(aggName2).toString());
            sourceBuilder.aggregation(sumBucket);
        }else{
            //无分组字段
            //指标有可能是数字，有可能是计数
            if (CollectionsUtil.isNotEmpty(summaryAttrList)) {
                for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
                    StringBuilder field = new StringBuilder();
                    String formId = fieldAttrPojo.getFormId().toString();
                    String attr = getAggNameAndField(fieldAttrPojo, isSingle, field, aggName2);
                    String fieldResult = field.toString();
                    if (attr.contains("count")) {
                        fieldResult = "id";
                        if (formIdAttr != null && formIdAttr.size() > 0) {
                            fieldResult = formIdAttr.getJSONObject(formId).getString(StringConstant.DATA_ID);
                            aggName2 = new StringBuilder(formId).append(aggName2);
                        }
                        AggregationBuilder countAggregationBuilder = AggregationBuilders.count(aggName2.toString()).field(fieldResult);
                        sourceBuilder.aggregation(countAggregationBuilder);
                        continue;
                    }
                    String aggType = fieldAttrPojo.getAggType();
                    AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                    //如果是计算字段，需要判断是否是计算字段
                    if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),fieldAttrPojo.getFieldType())) {
                        List<String> fieldsList = new ArrayList<>();
                        //判断单表还是多表，拼script
                        JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                        String formula = formulaInfo.getString("formula");
                        try {
                            formula = getString(sourceBuilder, formIdAttr, isSingle, fieldsList, formulaInfo, formula, Long.toString(fieldAttrPojo.getFormId()));
                        } catch (XbbException e) {
                            LOG.error("计算字段的公式格式有问题", e);
                            throw e;
                        }
                        switch (aggTypeEnum){
                            case SUM:
                                SumAggregationBuilder sum = AggregationBuilders.sum("totalSum").script(new Script(formula));
                                sourceBuilder.aggregation(sum);
                                break;
                            case AVG:
                                AvgAggregationBuilder avg = AggregationBuilders.avg("totalSum").script(new Script(formula));
                                sourceBuilder.aggregation(avg);
                                break;
                            case MAX:
                                MaxAggregationBuilder max = AggregationBuilders.max("totalSum").script(new Script(formula));
                                sourceBuilder.aggregation(max);
                                break;
                            case MIN:
                                MinAggregationBuilder min = AggregationBuilders.min("totalSum").script(new Script(formula));
                                sourceBuilder.aggregation(min);
                                break;
                            case COUNT:
                                ValueCountAggregationBuilder count = AggregationBuilders.count("totalSum").script(new Script(formula));
                                sourceBuilder.aggregation(count);
                                break;
                        }
                    }else{
                        getAggNameAndField(fieldAttrPojo, isSingle, field, aggName2);
                        switch (aggTypeEnum){
                            case SUM:
                                SumAggregationBuilder sum = AggregationBuilders.sum("totalSum").field(fieldResult);
                                sourceBuilder.aggregation(sum);
                                break;
                            case AVG:
                                AvgAggregationBuilder avg = AggregationBuilders.avg("totalSum").field(fieldResult);
                                sourceBuilder.aggregation(avg);
                                break;
                            case MAX:
                                MaxAggregationBuilder max = AggregationBuilders.max("totalSum").field(fieldResult);
                                sourceBuilder.aggregation(max);
                                break;
                            case MIN:
                                MinAggregationBuilder min = AggregationBuilders.min("totalSum").field(fieldResult);
                                sourceBuilder.aggregation(min);
                                break;
                            case COUNT:
                                ValueCountAggregationBuilder count = AggregationBuilders.count("totalSum").field(fieldResult);
                                sourceBuilder.aggregation(count);
                                break;
                        }
                    }
                }
            }
        }
        sourceBuilder.size(0);
    }

    /**
     * 将计算字段拼接成es
     * @param sourceBuilder
     * @param formIdAttr 多表映射
     * @param isSingle 单表标志
     * @param fieldsList 公式涉及到的变量
     * @param formulaInfo 公式相关参数
     * @param formula 公式信息
     * @param formId
     * @return
     * @throws XbbException
     */
    public static String getString(SearchSourceBuilder sourceBuilder, JSONObject formIdAttr, boolean isSingle, List<String> fieldsList, JSONObject formulaInfo, String formula, String formId) throws XbbException {
        String symbol = RegexUtil.extractFormulaName(formula);
        // 公司涉及到的参数list
        List<String> fieldList = new ArrayList<>();
        // 除数和被除数数组Map
        Map<String,Set<String>> divideMap = new TreeMap<>(new Comparator<String>(){
            @Override
            public int compare(String s1, String s2){
                Boolean flag1 = RegexUtil.matchOperationSymbol(s1);
                Boolean flag2 = RegexUtil.matchOperationSymbol(s2);
                if (Objects.equals(s1,s2)){
                    return 0;
                }else if (flag1 && flag2){
                    return s1.compareTo(s2);
                }else if (flag1){
                    return 1;
                }else if (flag2){
                    return -1;
                }else {
                    return s1.compareTo(s2);
                }
            }
        });
        formula = RegexUtil.formulaTranslate(formula,fieldList,divideMap);
        String symbolMath = null;
        if(Objects.equals(DATE_DIFF,symbol)){
            formula = getScriptString4Date(formId, formIdAttr, isSingle, formulaInfo, formula, fieldsList);
        }else {
            formula = getScriptString(formId, formIdAttr, isSingle, formulaInfo, formula, fieldsList,divideMap,fieldList);
        }
        BoolQueryBuilder queryBuilder = (BoolQueryBuilder) sourceBuilder.query();
//        if(StringUtil.isEmpty(symbolMath)){
//            for (String s : fieldsList) {
//                queryBuilder.filter(existsQuery(s));
//            }
//        }
        sourceBuilder.query(queryBuilder);
        return formula;
    }
    /**
     * 根据公式拼装script语句
     * @param formId 表单id
     * @param formIdAttr 多表映射
     * @param isSingle 单表标识
     * @param formulaInfo 公式相关参数
     * @param text
     * @param fieldsList
     * @param divideMap 除数涉及到的字段，key为除数，value为key涉及到的触发公式
     * @param fieldList 公式涉及到的字段
     * @return
     * @throws XbbException
     */
    public static String getScriptString(String formId, JSONObject formIdAttr, boolean isSingle, JSONObject formulaInfo, String text, List<String> fieldsList, Map<String,Set<String>> divideMap,List<String> fieldList) throws XbbException {
        // 定义一个originText存储原始的text，在combination方法需要用到原始originText
        // distinctFieldSet用于一个计算字段里面一个变量出现多次，会造成多次运算，去重
        // fieldSet用于存储加过doc['data.这些的field，用于后面的运算
        Set<String> distinctFieldSet = new HashSet<>();
        Set<String> fieldSet = new HashSet<>(fieldList);

        // 将text里面的{ 和 }和+转成特定的符号，用replaceAll方法时会有影响
        text = text.replaceAll("\\{","").replaceAll("\\}","");
        String originText = text;
        //先判断text左括号和右括号没有超过10
        JSONObject fieldsObject = formulaInfo.getJSONObject("fields");
        // 倒序一下
        for (String s : fieldsObject.keySet()) {
            //根据formId获取下面的字段
            JSONArray tempArray = fieldsObject.getJSONArray(s);
            //遍历该formId下的字段
            Collections.sort(tempArray, (o1, o2) -> {
                Integer num1 = Integer.parseInt(o1.toString().replaceAll("num_",""));
                Integer num2 = Integer.parseInt(o2.toString().replaceAll("num_",""));
                if(num1.compareTo(num2) >= 0){
                    return -1;
                }else {
                    return 1;
                }
            });
        }
        if (isSingle) {
            JSONArray fieldsArray = fieldsObject.getJSONArray(formId);
            for (int x = 0; x < fieldsArray.size(); x++) {
                String attrString = fieldsArray.getString(x);
                // 防止一个变量重复运算多次
                if (distinctFieldSet.contains(attrString)){
                    continue;
                }
                distinctFieldSet.add(attrString);
                StringBuilder sb = new StringBuilder("{doc['data.");
                StringBuilder sb1=new StringBuilder();
                sb1.append(formId).append(".").append(attrString);
                //8678.num_3 把8678去掉，再拼接。
                sb.append(attrString);
                sb.append("'].value}");
                // sbDistinctBraces为去除{}的sb
                // key 为匹配替换key的字符串
                // keyDistinctBraces为上者去掉{}的字符串
                // keyReplacement 为替换的字符串
                String sbDistinctBraces = sb.toString().replaceAll("\\{","").replaceAll("\\}","");
                String key = "{"+formId+"."+attrString+"}";
                String keyDistinctBraces = key.replaceAll("\\{","").replaceAll("\\}","");
                String keyReplacement = "doc['data." + attrString + "']";
                if (fieldList.contains(key)){
                    fieldSet.remove(key);
                    fieldSet.add(sb.toString().replaceAll(".value",""));
                }
                // 将text里面的旧变量替换成新的变量
                text = text.replaceAll(sb1.toString(), sbDistinctBraces);
                originText = originText.replaceAll(sb1.toString(), sbDistinctBraces);

                // 计算字段里面有除数的话要进入combination方法特殊处理
                // 将divideMap里面的key和value里面的变量替换
                if (divideMap.size()>0){
                    Map<String,Set<String>> tempDivideMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Iterator<Map.Entry<String,Set<String>>> iterator = divideMap.entrySet().iterator();
                    while(iterator.hasNext()){
                        Map.Entry<String,Set<String>> entry = iterator.next();
                        String k = entry.getKey();
                        Set<String> value = entry.getValue();
                        Set<String> tempValue = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        value.forEach(valueItem ->{
                            tempValue.add(valueItem.replaceAll(keyDistinctBraces,sb.toString()).replaceAll("\\{","").replaceAll("\\}",""));
                        });
                        tempDivideMap.put(k.replaceAll(keyDistinctBraces,keyReplacement).replaceAll("\\{","").replaceAll("\\}",""),tempValue);
                    }
                    divideMap.clear();
                    divideMap.putAll(tempDivideMap);
                }
            }
        } else {
            //s是formId
            for (String s : fieldsObject.keySet()) {
                //根据formId获取下面的字段
                JSONArray tempArray = fieldsObject.getJSONArray(s);
                //遍历该formId下的字段
                for (int y = 0; y < tempArray.size(); y++) {
                    String tempField = tempArray.getString(y);
                    // 防止一个变量重复运算多次
                    if (distinctFieldSet.contains(tempField)){
                        continue;
                    }
                    distinctFieldSet.add(tempField);
                    StringBuilder sb = new StringBuilder("{doc['");
                    StringBuilder sb1 = new StringBuilder("\\{");
                    sb1.append(s).append(".").append(tempField).append("\\}");
                    JSONObject tempJsonObject = formIdAttr.getJSONObject(s);
                    String tempString = tempJsonObject.getString(tempField);
                    sb.append(tempString).append("'].value}");
                    // 匹配fieldList的key
                    // keyDistinctBraces去掉{}的key
                    // replacement要替换的字符串
                    String containsKey =  "{" + s + "." + tempField + "}";
                    String keyDistinctBraces = s + "." + tempField;
                    String replacement = "doc['" + tempString + "'].value";
                    String addField= sb.toString().replaceAll(".value","");
                    if (fieldList.contains(containsKey)){
                        fieldSet.remove(containsKey);
                        // fieldSet里面要用心的field，tempJsonObject里面里面的tempString，去掉.value，下面运算匹配需要
                        fieldSet.add(addField);
                    }
                    // 将text里面的旧变量替换成新的变量
                    text = text.replaceAll(keyDistinctBraces,replacement);
                    originText = originText.replaceAll(keyDistinctBraces, replacement);

                    // 计算字段里面有除数的话要进入combination方法特殊处理
                    // 将divideMap里面的key和value里面的变量替换
                    if (divideMap.size()>0){
                        Map<String,Set<String>> tempDivideMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Iterator<Map.Entry<String,Set<String>>> iterator = divideMap.entrySet().iterator();
                        while(iterator.hasNext()){
                            Map.Entry<String,Set<String>> entry = iterator.next();
                            String k = entry.getKey();
                            Set<String> value = entry.getValue();
                            Set<String> tempValue = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            value.forEach(valueItem ->{
                                tempValue.add(valueItem.replaceAll(keyDistinctBraces,replacement).replaceAll("\\{","").replaceAll("\\}",""));
                            });
                            tempDivideMap.put(k.replaceAll(keyDistinctBraces,replacement).replaceAll("\\{","").replaceAll("\\}",""),tempValue);
                        }
                        divideMap.clear();
                        divideMap.putAll(tempDivideMap);
                    }
                }
            }
        }
        // 将旧数据删掉
        fieldSet.removeIf(item -> !item.replaceAll("\\{","").replaceAll("\\}","").contains("doc"));

        // defSb循环变量fieldList给非常量数组赋默认值0
        // ifSb判断变量是否存在有值，给defSb里面的数组重新赋值
        StringBuilder defSb = new StringBuilder("def num = [");
        StringBuilder ifSb = new StringBuilder();

        // fieldList重新赋值为fieldSet
        // fieldIndexMap用于定位变量在num数组的位置
        fieldList = new ArrayList<>(fieldSet);
        Map<String,Integer> fieldIndexMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 拼接defSb和ifSb
        for (int i = 0; i < fieldList.size(); i++) {
            String field = fieldList.get(i).replaceAll("\\{","").replaceAll("\\}","");
            defSb.append("0,");
            ifSb.append("if(").append(field).append(".size() !=0){num["+i+"]=").append(field).append(".value;").append("}");
            fieldIndexMap.put(field,i);
        }
        if (fieldList.size()>0){
            defSb = new StringBuilder().append(defSb.substring(0,defSb.toString().length()-1));
        }
        defSb.append("];");

        // 如果计算字段里面包含除数特殊处理
        Stack<String> stack = new Stack<>();
        StringBuffer stringBuffer = new StringBuffer();
        if (divideMap.size()>0){
            for (int i = divideMap.size(); i >0; i--) {
                combination2(divideMap,i,0,0,stringBuffer,stack,text,formId,formIdAttr,isSingle,fieldsObject);
            }
            stringBuffer.append("else{"+ originText.replaceAll("\\{","").replaceAll("\\}","") + "}");
        }
        String stringBufferStr = stringBuffer.toString().replaceAll("doc","").replaceAll(".value","");
        originText = originText.replaceAll("doc","").replaceAll(".value","");
        // 将stringBuffer里面的变量用def声明的变量替换
        for (Map.Entry<String, Integer> entry : fieldIndexMap.entrySet()) {
            String k = entry.getKey();
            Integer v = entry.getValue();
            k = k.replaceAll("doc","");
            k = RegexUtil.transferSpecialSymbol(k);
            stringBufferStr = stringBufferStr.replaceAll(k,"num["+v+"]");
            originText = originText.replaceAll(k,"num["+v+"]");
        }

        // 拼接text
        if (divideMap.size()>0){
            text = defSb.append(ifSb).append(stringBufferStr).toString();
        }else {
            text = defSb.append(ifSb).append(stringBufferStr).append(originText).toString();
        }

        // 将text里面的一些字符串转化回来
        if (text.length() > PaasConstant.ES_SCRPIT_LENGTH){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224077);
        }
        return text;
    }

    /**
     * 对计算字段进行组合
     * @param divideMap  待选Map
     * @param target 要选几个值
     * @param has 当前栈里有几个
     * @param cur  当前选到的下标
     * @param stringBuffer  拼装好的数据
     * @param stack 临时存储栈
     */
    private static void combination2(Map<String,Set<String>> divideMap, int target, int has, int cur, StringBuffer stringBuffer, Stack<String> stack,String text,String formId, JSONObject formIdAttr, boolean isSingle,JSONObject fieldsObject) {
        List<String> fieldList = new ArrayList<>(divideMap.keySet());
        String originText = text;
        if(has == target) {
            if(fieldList.size() == target){
                stringBuffer.append("if(");
            }else {
                stringBuffer.append("else if(");
            }
            StringBuffer inBuffer = new StringBuffer();
            inBuffer.append("{(");
            List<String> tempAppendList = new ArrayList<>();
            for (int i = 0; i < fieldList.size(); i++) {
                String s = fieldList.get(i);
                s = s.replaceAll("\\{","").replaceAll("\\}","");
                String field = s.substring(s.indexOf("&")+1);
                if (tempAppendList.contains(field)){
                    continue;
                }
                tempAppendList.add(field);
//                if (i!=0){
//                    stringBuffer.append(" && ");
//                }
                if(stack.contains(s)){
                    if (RegexUtil.matchOperationSymbol(field)){
                        for (String item : tempAppendList) {
                            if (!RegexUtil.matchOperationSymbol(item) && s.contains("/"+item)){
                                field = field.replaceAll(RegexUtil.transferSpecialSymbol("\\/"+item),"/0");
                                int index = -1;
                                while((index = field.indexOf("/0")) != -1){
                                    int tempIndex = field.substring(0,index).lastIndexOf("(");
                                    if (tempIndex !=-1){
                                        field = field.substring(0,tempIndex) + field.substring(index+3);
                                    }
                                }
                            }
                        }
                    }
                    if (!"".equals(field.replaceAll("\\(","").replaceAll("\\)",""))){
                        if (i!=0){
                            stringBuffer.append(" && ");
                        }
                        stringBuffer.append(field +" ==0.0 ");
                    }
                    Set<String> replacedFormulaSet = divideMap.get(field);
                    if (CollectionsUtil.isNotEmpty(replacedFormulaSet)){
                        for (String item : replacedFormulaSet) {
                            item = RegexUtil.transferSpecialSymbol(item);
                            text = text.replaceAll(item, "0");
                        }
                    }
                }else {
                    if (i!=0){
                        stringBuffer.append(" && ");
                    }
                    stringBuffer.append(field +" !=0.0 ");
                }
            }
            if (StringUtil.isEmpty(text)){
                text = "0";
            }
            text = RegexUtil.filterLogicalOperationsSymbol(text);
            stringBuffer.append(")");
            inBuffer.append(text);
            inBuffer.append(")}");
            stringBuffer.append(inBuffer);

            boolean flag = true;
            for (int i = fieldList.size() - 1; i >= fieldList.size()-target; i--) {
                if(!stack.contains(fieldList.get(i))){
                    flag = false;
                }
            }
            return;
        }

        for(int i=cur;i<fieldList.size();i++) {
            if(!stack.contains(fieldList.get(i).replaceAll("\\{","").replaceAll("\\}",""))) {
                stack.add(fieldList.get(i).replaceAll("\\{","").replaceAll("\\}",""));
                combination2(divideMap, target, has+1, i,stringBuffer,stack,originText,formId,formIdAttr,isSingle,fieldsObject);
                stack.pop();
            }
        }

    }

    /**
     * 日期公式
     * @param formId
     * @param formIdAttr 暂时不用
     * @param isSingle 是否是单表
     * @param formulaInfo 公式信息
     * @param text 暂时不用
     * @param fieldsList 公式里面涉及的字段
     * @return
     * @throws XbbException
     */
    public static String getScriptString4Date(String formId, JSONObject formIdAttr, boolean isSingle, JSONObject formulaInfo, String text, List<String> fieldsList) throws XbbException {
        //先判断text左括号和右括号没有超过10
        JSONObject fieldsObject = formulaInfo.getJSONObject("fields");
        text = formulaInfo.getString("formula");
        // 截取出单位
        if (StringUtil.isEmpty(text) || text.length()< 2){
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241017);
        }
        String unit = DateDiffTypeEnum.DAY.getAlias();
        String textTemp = text.substring(1,text.length()-1);
        int startIndex;
        if (textTemp.lastIndexOf(PaasConstant.LEFT_BRACE) < (startIndex = textTemp.lastIndexOf(PaasConstant.COMMAS))){
            unit = textTemp.substring(startIndex + 1).replaceAll("\"","");
        }
        if (!DateDiffTypeEnum.list().contains(unit)){
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241017);
        }
        // 第一个日期信息
        String dataAttr = "";
        // 第二个日期信息
        String dataAttr2 = "";
        if (isSingle) {
            JSONArray fieldsArray = fieldsObject.getJSONArray(formId);
            // 日期没有两个参数，返回0
            if (fieldsArray.size() < PaasConstant.DATE_PARAM_NUM){
                return "0";
            }
            // 第一个日期信息
            dataAttr = fieldsArray.getString(0);
            // 第二个日期信息
            dataAttr2 = fieldsArray.getString(1);
            if (!FieldTypeEnum.getDateSpecialAlias().contains(dataAttr)){
                dataAttr = "data." + dataAttr;
            }
            if (!FieldTypeEnum.getDateSpecialAlias().contains(dataAttr2)){
                dataAttr2 = "data." + dataAttr2;
            }
            fieldsList.add(dataAttr);
//            fieldsList.add(dataAttr2);
        } else {
            //s是formId
            for (String s : fieldsObject.keySet()) {
                //根据formId获取下面的字段
                JSONArray tempArray = fieldsObject.getJSONArray(s);
                //遍历该formId下的字段
                for (int y = 0; y < tempArray.size(); y++) {
                    String tempField = tempArray.getString(y);
                    if (!FieldTypeEnum.getDateSpecialAlias().contains(tempField)){
                        tempField = "data." + tempField;
                    }
                    if (StringUtil.isEmpty(dataAttr)){
                        dataAttr = s + "." + tempField;
//                        fieldsList.add(dataAttr);
                    }else if (StringUtil.isEmpty(dataAttr2)){
                        dataAttr2 = s + "." + tempField;
//                        fieldsList.add(dataAttr2);
                    }else {
                        break;
                    }
                }
            }
            if (StringUtil.isEmpty(dataAttr) || StringUtil.isEmpty(dataAttr2)){
                return "0";
            }
        }
        // 拼接成script
        StringBuilder sb = new StringBuilder();
        sb.append("if(doc['" + dataAttr + "'].size() == 0 || doc['" + dataAttr2 + "'].size() == 0){0}else{");
        DateDiffTypeEnum typeEnum = DateDiffTypeEnum.getByAlias(unit);
        switch (typeEnum){
            case YEAR:
                sb.append("doc['" + dataAttr + "'].value.getYear() - doc['" + dataAttr2 + "'].value.getYear() + ");
                sb.append("(doc['" + dataAttr + "'].value.getMonthValue() - doc['" + dataAttr2 + "'].value.getMonthValue())/12.0 +");
                sb.append("(doc['" + dataAttr + "'].value.getDayOfMonth() - doc['" + dataAttr2 + "'].value.getDayOfMonth())/(1.0 * (LocalDate.from(doc['" + dataAttr2 + "'].value).with(TemporalAdjusters.lastDayOfYear()).getDayOfYear())) +");
                sb.append("(doc['" + dataAttr + "'].value.getMillisOfDay() - doc['" + dataAttr2 + "'].value.getMillisOfDay()) / ((LocalDate.from(doc['" + dataAttr2 + "'].value).with(TemporalAdjusters.lastDayOfYear()).getDayOfYear())*(1000.0 * 60 * 60 * 24))");
                break;
            case MONTH:
                sb.append("(doc['" + dataAttr + "'].value.getYear() - doc['" + dataAttr2 + "'].value.getYear()) * 12 + ");
                sb.append("doc['" + dataAttr + "'].value.getMonthValue() - doc['" + dataAttr2 + "'].value.getMonthValue() +");
                sb.append("(doc['" + dataAttr + "'].value.getDayOfMonth() - doc['" + dataAttr2 + "'].value.getDayOfMonth())/(1.0 * (LocalDate.from(doc['" + dataAttr2 + "'].value).with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth())) +");
                sb.append("(doc['" + dataAttr + "'].value.getMillisOfDay() - doc['" + dataAttr2 + "'].value.getMillisOfDay()) / ((LocalDate.from(doc['" + dataAttr2 + "'].value).with(TemporalAdjusters.lastDayOfYear()).getDayOfYear())*(1000.0 * 60 * 60 * 24))");
                break;
            case DAY:
                sb.append("(doc['" + dataAttr + "'].value.getMillis() - doc['" + dataAttr2 + "'].value.getMillis()) / (1000.0 * 24 * 60 * 60)");
                break;
            case HOUR:
                sb.append("(doc['" + dataAttr + "'].value.getMillis() - doc['" + dataAttr2 + "'].value.getMillis()) / (1000.0 * 60 * 60)");
                break;
            case MINUTE:
                sb.append("(doc['" + dataAttr + "'].value.getMillis() - doc['" + dataAttr2 + "'].value.getMillis()) / (1000.0 * 60)");
                break;
            case SECOND:
                sb.append("(doc['" + dataAttr + "'].value.getMillis() - doc['" + dataAttr2 + "'].getMillis()) / 1000.0");
                break;
            case UNKNOWN:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224076);
        }
        sb.append("}");
        fieldsList.clear();
        return sb.toString();
    }
    public static void esSortByFiled(Object builder, Map<String, String> sortMap, Map<JSONObject, FieldAttrPojo> parseAttrMap, List<FieldAttrPojo> summaryAttrList, ChartEntity chartEntity) {
        SearchSourceBuilder searchSourceBuilder = null;
        TermsAggregationBuilder aggregationBuilder = null;
        boolean isSingle = !Objects.equals(chartEntity.getMuti(), BasicConstant.ZERO);
        boolean isContains = false;
        if (summaryAttrList != null) {
            for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
                String attr = fieldAttrPojo.getAttr();
                if (StringUtil.isNotEmpty(sortMap.get("field"))) {
                    String field = sortMap.get("field");
                    if (field.contains(attr)) {
                        isContains = true;
                    }
                }
            }
            if (!isContains) {
                return;
            }
        }
        SortOrder order = SortOrder.DESC;
        String sortField = "updateTime";
        String raw = ".raw";
        boolean mulTable = false;
        if (sortMap != null && !sortMap.isEmpty()) {
            if (builder instanceof SearchSourceBuilder) {
                searchSourceBuilder = (SearchSourceBuilder) builder;
                sortField = (StringUtil.isEmpty(sortMap.get("field")) ? sortField : sortMap.get("field"));
                String[] sortFieldStr = sortField.split("&");
                String type = null;
                String location = null;
                if (sortFieldStr.length > BasicConstant.TWO) {
                    type = sortFieldStr[2];
                    sortField = sortFieldStr[1];
                    location = sortFieldStr[0];
                    mulTable = true;
                }
                if (BasicConstant.TWO.equals(sortFieldStr.length)) {
                    type = sortFieldStr[1];
                    sortField = sortFieldStr[0];
                }
                if (StringUtil.isNotEmpty(type)) {
                    FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(Integer.valueOf(type));
                    if (fieldTypeEnum != null) {
                        if (FieldTypeEnum.TEXT.getEsalias().equals(fieldTypeEnum.getEsalias())) {
                            sortField = sortField + raw;
                        }
                        //系统字段不用加data.
                        if (!BelongEnum.SYSTEM.getAlias().equals(fieldTypeEnum.getBelong())) {
                            sortField = isSingle ? "data." + sortField : sortField;
                            if (mulTable) {
                                sortField = location + sortField;
                            }
                        } else {
                            if (mulTable) {
                                sortField = location + sortField;
                            }
                        }
                    }
                }
            } else if (builder instanceof TermsAggregationBuilder) {
                aggregationBuilder = (TermsAggregationBuilder) builder;
                sortField = sortMap.get("field");
            }
            // } else {
            // 排序不存在字段列表中时，给定默认排序，以防报错
            // sortField = "updateTime";
            //}
            if (SortOrder.ASC.toString().equals(sortMap.get(BasicConstant.SORT))) {
                order = SortOrder.ASC;
            }
        }
        if (searchSourceBuilder != null) {
            //如果查询表的计算字段需要排序
            if (sortField.contains("computedField")) {
                JSONArray displayAttr = chartEntity.getDisplayAttr();
                Script script = null;
                for (int i = 0; i < displayAttr.size(); i++) {
                    JSONObject jsonObject = displayAttr.getJSONObject(i);
                    if (sortField.contains(jsonObject.getString("attr"))) {
                        for (Map.Entry<JSONObject, FieldAttrPojo> jsonObjectFieldAttrPojoEntry : parseAttrMap.entrySet()) {
                            JSONObject key = jsonObjectFieldAttrPojoEntry.getKey();
                            if (key.getString("key").contains(jsonObject.getString("attr"))) {
                                FieldAttrPojo value = jsonObjectFieldAttrPojoEntry.getValue();
                                script = new Script(value.getFormulaInfo().getString("formula"));
                            }
                        }
                        break;
                    }
                }
                SortBuilder sortBuilder = new ScriptSortBuilder(script,ScriptSortBuilder.ScriptSortType.NUMBER).order(order);
                searchSourceBuilder.sort(sortBuilder);
            }else{
                searchSourceBuilder.sort(new FieldSortBuilder(sortField).order(order));
            }
        } else if (aggregationBuilder != null) {
            boolean aggOrder = false;
            if (order.equals(SortOrder.ASC)) {
                aggOrder = true;
            }
            aggregationBuilder.order(BucketOrder.aggregation(sortField, aggOrder));
        }
    }

    public static void esSortStatisticsByFiled(ValuesSourceAggregationBuilder builder, Map<String, String> sortMap, List<FieldAttrPojo> summaryAttrList, ChartEntity chartEntity) {
        if (summaryAttrList == null || summaryAttrList.size() == 0 || sortMap == null) {
            return;
        }
        boolean isSingle = !Objects.equals(chartEntity.getMuti(), BasicConstant.ZERO);
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
            Integer fieldType = fieldAttrPojo.getFieldType();
            FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldType);
            String attr = fieldAttrPojo.getAttr();
            Integer groupIndex = fieldAttrPojo.getGroupIndex();
            String asc = sortMap.get(attr + "&"+ fieldType + "&" + fieldAttrPojo.getFormId());
            if (asc == null) {
                attr = attr + "&" + fieldType;
                asc = sortMap.get(attr);
            }
            if (asc == null || Objects.equals(asc, "default")) {
                continue;
            }
            boolean ascFlag = Objects.equals(asc, StringConstant.SORT_ASC_TAG);
            String aggName = attr;
            aggName = aggName.contains("&") ? aggName : aggName + "&" + fieldAttrPojo.getFieldType();
            if (fieldTypeEnum == null) {
                continue;
            }
            if (Objects.equals(fieldTypeEnum.getAlias(), BelongEnum.SYSTEM.getAlias()) && isSingle) {
                aggName = "data." + aggName;
            }
            if (!isSingle && formIdAttr != null && formIdAttr.size() > 0 && Objects.equals(fieldType, FieldTypeEnum.COUNT.getType())) {
                aggName = fieldAttrPojo.getFormId().toString() + aggName;
            }
            // 放开可重复字段
            if (Objects.nonNull(groupIndex)) {
                aggName = aggName + "&" + groupIndex;
            }
            if (builder instanceof DateHistogramAggregationBuilder) {
                ((DateHistogramAggregationBuilder) builder).order(BucketOrder.aggregation(aggName, ascFlag));
            } else if (builder instanceof TermsAggregationBuilder) {
                ((TermsAggregationBuilder) builder).order(BucketOrder.aggregation(aggName, ascFlag));
            }
        }
    }

    public static void esSortChartStatisticsByFiled(ValuesSourceAggregationBuilder builder, Map<String, String> sortMap, FieldAttrPojo fieldAttrPojo,String side,Integer sortIndex,String sortMapKey) {
        if (sortMap == null) {
            return;
        }
        Integer fieldType = fieldAttrPojo.getFieldType();
        String attr = fieldAttrPojo.getAttr();
        String asc = null;
        if (Objects.nonNull(sortMapKey)){
            asc = sortMap.get(sortMapKey);
        }else {
            asc = sortMap.get(attr);
        }
        if (asc == null) {
            attr = attr + "&" + fieldType;
            asc = sortMap.get(attr);
        }
        if (asc == null && !Objects.equals(fieldAttrPojo.getAttr(),"count")) {
            Integer sideFlag = Objects.equals(side,PaasConstant.LEFT) ? 0 : 1;
            attr = attr + "&" + sideFlag;
            asc = sortMap.get(attr);
        }
        if (asc == null && Objects.equals(fieldAttrPojo.getAttr(),"count")) {
            Integer sideFlag = Objects.equals(side,PaasConstant.LEFT) ? 0 : 1;
            attr = attr + "&" + fieldAttrPojo.getFormId() + "&" + sideFlag;
            asc = sortMap.get(attr);
        }
        if (asc == null || Objects.equals(asc, "default")) {
            return;
        }
        boolean ascFlag = Objects.equals(asc, StringConstant.SORT_ASC_TAG);
        if (Objects.isNull(side) && Objects.isNull(sortIndex)){
            if (builder instanceof DateHistogramAggregationBuilder) {
                if (Objects.equals(fieldType, FieldTypeEnum.COUNT.getType())) {
                    ((DateHistogramAggregationBuilder) builder).order(BucketOrder.aggregation("_count", ascFlag));
                } else {
                    ((DateHistogramAggregationBuilder) builder).order(BucketOrder.aggregation("sum_total", ascFlag));
                }
            } else if (builder instanceof TermsAggregationBuilder) {
                if (Objects.equals(fieldType, FieldTypeEnum.COUNT.getType())) {
                    ((TermsAggregationBuilder) builder).order(BucketOrder.count(ascFlag));
                } else {
                    ((TermsAggregationBuilder) builder).order(BucketOrder.aggregation("sum_total", ascFlag));
                }
            }
        }else {
            if (builder instanceof DateHistogramAggregationBuilder) {
                if (Objects.equals(fieldType, FieldTypeEnum.COUNT.getType())) {
                    ((DateHistogramAggregationBuilder) builder).order(BucketOrder.count(ascFlag));
//                    ((DateHistogramAggregationBuilder) builder).order(BucketOrder.aggregation("_count" + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() +  "&" + side + "&" + sortIndex, ascFlag));
                } else {
                    ((DateHistogramAggregationBuilder) builder).order(BucketOrder.aggregation("sum_total" + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() +  "&" + side + "&" + sortIndex, ascFlag));
                }
            } else if (builder instanceof TermsAggregationBuilder) {
                if (Objects.equals(fieldType, FieldTypeEnum.COUNT.getType())) {
                    ((TermsAggregationBuilder) builder).order(BucketOrder.count(ascFlag));
//                    ((TermsAggregationBuilder) builder).order(BucketOrder.aggregation("sum_total" + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() +  "&" + side + "&" + sortIndex,ascFlag));
                } else {
                    ((TermsAggregationBuilder) builder).order(BucketOrder.aggregation("sum_total" + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() +  "&" + side + "&" + sortIndex, ascFlag));
                }
            }
        }

    }

    /**
     * 解析自定义图表查询条件
     * @param boolQueryBuilder
     * @param chartEntity
     * @throws XbbException
     */
/*
    public static boolean parseConditionIntersection(BoolQueryBuilder boolQueryBuilder, ChartEntity chartEntity, boolean isPublicFlag) throws XbbException {
        JSONArray conditionJson = chartEntity.getFilter();
        JSONArray searchJson = chartEntity.getSearch();
        JSONObject formIdAttr = chartEntity.getFormIdAttr();

        //获取formId和saasMark的对应关系，团队处理需要区别saas表和paas表
        JSONObject driveSources = chartEntity.getDriverSources();
        JSONArray slaveSources = chartEntity.getSlaveSources();
        Map<Integer, Boolean> sourcesMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        boolean isTeamLogic = isTeamLogicByBusinessType(driveSources.getInteger("businessType"));
        sourcesMap.put(driveSources.getInteger("formId"),isTeamLogic);
        if(slaveSources!=null) {
            for (int i = 0; i < slaveSources.size(); i++) {
                JSONObject slaveSource = slaveSources.getJSONObject(i);
                boolean isTeamLogicSlave = isTeamLogicByBusinessType(slaveSource.getInteger("businessType"));
                sourcesMap.put(slaveSource.getInteger("formId"), isTeamLogicSlave);
            }
        }
        //这里会有三种情况 查询条件存在，筛选条件存在，两者都存在
        Map<String,ConditionsContainerExt> filterConditionMap = parseCustomCondition(conditionJson, formIdAttr);
        Map<String,ConditionsContainerExt> searchConditionMap = parseCustomCondition(searchJson, formIdAttr);
        if(filterConditionMap.size()==0 && searchConditionMap.size()>0){
            parseFilterOrSearchCondition(boolQueryBuilder,searchJson,formIdAttr,false,sourcesMap,false);
            return true;
        }else if(searchConditionMap.size()==0 && filterConditionMap.size()>0){
            parseFilterOrSearchCondition(boolQueryBuilder,conditionJson,formIdAttr,true,sourcesMap,isPublicFlag);
            return true;
        }else if(searchConditionMap.size()==0){
            return true;
        }
        Map<String,ConditionsContainerExt> copyFilter = new HashMap<>(filterConditionMap);
        Map<String,ConditionsContainerExt> copySearch = new HashMap<>(searchConditionMap);
        Set<String> filterMixSet = copyFilter.keySet();
        Set<String> searchMixSet = copySearch.keySet();
        filterMixSet.retainAll(searchMixSet);
        boolean noIntersection = true;
        if(filterMixSet.size()==0){
            //没有相关联的 直接进行筛选或查询
            parseFilterOrSearchCondition(boolQueryBuilder, conditionJson, formIdAttr, true, sourcesMap, false);
            parseFilterOrSearchCondition(boolQueryBuilder, searchJson, formIdAttr, false, sourcesMap, false);
        }
        Iterator<String> it = filterMixSet.iterator();
        List<ConditionsContainerExt> conditionsList = new ArrayList<>();
        List<ConditionsContainerExt> conditionsEntityList = new ArrayList<>();
        while (it.hasNext()){
            String key = it.next();
            ConditionsContainerExt filterCondition = copyFilter.get(key);
            ConditionsContainerExt searchCondition = copySearch.get(key);
            ConditionEnum filterConditionEnum = ConditionEnum.getConditionEnum(filterCondition.getSymbol());
            FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(searchCondition.getFieldType());
            if(filterConditionEnum!=null&&fieldTypeEnum!=null) {
                noIntersection = intersectionCondition(conditionsList, filterCondition, searchCondition, filterConditionEnum, fieldTypeEnum);

            }
            //只要有一条无交集则不让参与Es查询
            if (noIntersection){
                return false;
            }else {
                conditionsEntityList.addAll(conditionsList);
                filterConditionMap.remove(key);
                searchConditionMap.remove(key);
            }
        }
        //有交集继续走下面的逻辑
        if(!noIntersection) {
            conditionsList.clear();
            Iterator<Map.Entry<String, ConditionsContainerExt>> filterIt = filterConditionMap.entrySet().iterator();
            Iterator<Map.Entry<String, ConditionsContainerExt>> searchIt = searchConditionMap.entrySet().iterator();
            while (filterIt.hasNext()) {
                ConditionsContainerExt containerExt = filterIt.next().getValue();
                conditionsEntityList.add(containerExt);
            }
            while (searchIt.hasNext()) {
                ConditionsContainerExt containerExt = searchIt.next().getValue();
                conditionsList.add(containerExt);
            }
            //拿出来统一解析 在无交集时效率高一点
            for (ConditionsContainerExt conditionsContainerExt : conditionsEntityList) {
                ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(conditionsContainerExt.getSymbol());
                boolean isTeam = sourcesMap.get(conditionsContainerExt.getFormId().intValue());
                conditionSymbolChoose(boolQueryBuilder, conditionEnum, conditionsContainerExt, isTeam,false);

            }
            for (ConditionsContainerExt conditionsContainerExt : conditionsList) {
                FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(conditionsContainerExt.getFieldType());
                boolean isTeam = sourcesMap.get(conditionsContainerExt.getFormId().intValue());
                conditionSymbolChoose(boolQueryBuilder, fieldTypeEnum, conditionsContainerExt, isTeam);
            }
        }
        return true;
    }
*/
    public static boolean parseConditionIntersection(BoolQueryBuilder boolQueryBuilder, ChartEntity chartEntity,  boolean isPublicFlag) throws XbbException {
        JSONArray conditionJson = chartEntity.getFilter();
        conditionJson = Objects.isNull(conditionJson) ? new JSONArray() : conditionJson;
        JSONArray searchJson = chartEntity.getSearch();
        boolean isSingle;
        if (chartEntity.getSingle() == null) {
            isSingle = true;
        } else {
            isSingle =getSingle(chartEntity);
        }
        if (searchJson != null && searchJson.size() > 0) {
            //查询条件和筛选条件放在一起
            conditionJson.addAll(searchJson);
        }
        // 筛选条件处理常用和自定义动态
        if (CollectionsUtil.isNotEmpty(conditionJson)) {
            for (int i = 0; i < conditionJson.size(); i++) {
                JSONObject conditionObj = conditionJson.getJSONObject(i);
                handleNormalOrCustomFilter(chartEntity, conditionObj);
            }
        }
        //获取formId和saasMark的对应关系，团队处理需要区别saas表和paas表
        JSONObject driveSources = chartEntity.getDriverSources();
        JSONArray slaveSources = chartEntity.getSlaveSources();
        Map<Integer, Boolean> sourcesMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        boolean isTeamLogic = EsHelper.isTeamLogicByBusinessType(driveSources.getInteger("businessType"));
        sourcesMap.put(driveSources.getInteger("formId"), isTeamLogic);
        if (slaveSources != null) {
            for (int i = 0; i < slaveSources.size(); i++) {
                JSONObject slaveSource = slaveSources.getJSONObject(i);
                boolean isTeamLogicSlave = EsHelper.isTeamLogicByBusinessType(slaveSource.getInteger("businessType"));
                sourcesMap.put(slaveSource.getInteger("formId"), isTeamLogicSlave);
            }
        }
        if (!isSingle) {
            if (conditionJson.size() > 0) {
                for (Object o : conditionJson) {
                    JSONObject filterJson = (JSONObject) o;
                    Integer fieldType = filterJson.getInteger("fieldType");
                    Long formId = filterJson.getLong("formId");
                    boolean isTeam = sourcesMap.get(formId.intValue());
                    boolean isTeamAttr = FieldTypeEnum.OWNERID.getType().equals(fieldType) || FieldTypeEnum.COUSERID.getType().equals(fieldType);
                    if (isTeam && isTeamAttr) {
                        int teamIdx = getTeamIdx(chartEntity, formId);
                        String teamAttr = "myTeam_" + teamIdx;
                        filterJson.put("attr", teamAttr);
                    }
                }
            }
        }

        parseFilterOrSearchCondition(boolQueryBuilder, conditionJson, isSingle, true, sourcesMap, isPublicFlag);
        return true;
    }

    /**
     * 动态时间（自定义和常用）筛选处理
     * @param chartEntity
     * @param conditionObj
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2022/1/19 13:40
     * @version 1.0
     */
    public static void handleNormalOrCustomFilter(ChartEntity chartEntity, JSONObject conditionObj) throws XbbException {
        // 常用
        if (Objects.equals(conditionObj.getString("symbol"), ConditionEnum.NORMAL.getSymbol())) {
            Map<String, Long> normalFilterResultMap = handleNormalFilter(conditionObj);
            Long startTimestamp = normalFilterResultMap.get("startTimestamp");
            Long endTimestamp = normalFilterResultMap.get("endTimestamp");
            if (Objects.isNull(startTimestamp) && Objects.isNull(endTimestamp)) {
                return;
            }
            if (Objects.isNull(startTimestamp)) {
                // 转成小于等于
                conditionObj.put("symbol", ConditionEnum.LESSEQUAL.getSymbol());
                conditionObj.put("value", Arrays.asList(endTimestamp));
            } else if (Objects.isNull(endTimestamp)) {
                // 转成大于等于
                conditionObj.put("symbol", ConditionEnum.GREATEREQUAL.getSymbol());
                conditionObj.put("value", Arrays.asList(startTimestamp));
            } else {
                // 转成range
                conditionObj.put("symbol", ConditionEnum.RANGE.getSymbol());
                conditionObj.put("value", Arrays.asList(startTimestamp, endTimestamp));
            }
        } else if (Objects.equals(conditionObj.getString("symbol"), ConditionEnum.CUSTOM.getSymbol())) {
            // 自定义
            JSONObject dynamicDate = conditionObj.getJSONObject("dynamicDate");
            // 处理开始时间
            Integer startType = dynamicDate.getInteger("startType");
            Integer startWay = dynamicDate.getInteger("startWay");
            Integer startTime = dynamicDate.getInteger("startTime");
            Long startTimestamp = handleDynamicDate(startType, startWay, startTime, true);
            // 处理结束时间
            Integer endType = dynamicDate.getInteger("endType");
            Integer endWay = dynamicDate.getInteger("endWay");
            Integer endTime = dynamicDate.getInteger("endTime");
            Long endTimestamp = handleDynamicDate(endType, endWay, endTime, false);
            // 校验
            if (Objects.nonNull(startTimestamp) && Objects.nonNull(endTimestamp)
                    && DateTimeUtil.differenceInDays(startTimestamp, endTimestamp) > TimeConstant.LEAP_YEAR) {
                LOG.error("corpid:" + chartEntity.getCorpid() + ",chartId:" + chartEntity.getId() + ",动态时间筛选超过一年");
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224078, StatisticsServicesErrorCodeEnum.API_ERROR_224078.getMsg(), ConditionEnum.CUSTOM.getMemo());
            }
            // 转成range
            conditionObj.put("symbol", ConditionEnum.RANGE.getSymbol());
            conditionObj.put("value", Arrays.asList(startTimestamp, endTimestamp));
        }
    }

    /**
     * 处理常用筛选
     * @param conditionObj
     * @return java.util.Map<java.lang.String, java.lang.Long>
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/10/14 16:39
     * @version 1.0
     */
    private static Map<String, Long> handleNormalFilter(JSONObject conditionObj) {
        Map<String, Long> result = new HashMap<>(2);
        Long startTimestamp = null;
        Long endTimestamp = null;
        Long startOfDay = DateTimeUtil.getStartOfDay(DateUtil.getNow());
        Long endOfDay = DateTimeUtil.getEndOfDay(DateUtil.getNow());
        Integer normalType = conditionObj.getInteger("normalType");
        NormalTypeEnum normalTypeEnum = NormalTypeEnum.getByCode(normalType);
        switch (normalTypeEnum) {
            case YESTERDAY:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(startOfDay, -1, Calendar.DATE);
                endTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, -1, Calendar.DATE);   
                break;
            case TODAY:
                startTimestamp = startOfDay;
                endTimestamp = endOfDay;
                break;
            case TOMORROW:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(startOfDay, 1, Calendar.DATE);
                endTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, 1, Calendar.DATE);
                break;
            case AFTER_TODAY:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, 1, Calendar.DATE);
                break;
            case LAST_WEEK:
                startTimestamp = DateTimeUtil.getLastWeekMondayInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getWeekMorningInSomeday(endOfDay);
                break;
            case THIS_WEEK:
                startTimestamp = DateTimeUtil.getWeekMorningInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getWeekSundayInSomeday(endOfDay);
                break;
            case NEXT_WEEK:
                startTimestamp = DateTimeUtil.getWeekSundayInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getNextWeekSundayInSomeday(endOfDay);
                break;
            case LAST_MONTH:
                startTimestamp = DateTimeUtil.getFirstDateOfLastMonth(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfLastMonth(endOfDay);
                break;
            case THIS_MONTH:
                startTimestamp = DateTimeUtil.getFirstDateOfThisMonth();
                endTimestamp = DateTimeUtil.getLastDateOfThisMonth();
                break;
            case NEXT_MONTH:
                startTimestamp = DateTimeUtil.getLastDateOfMonthInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfNextMonthInSomeday(endOfDay);
                break;
            case LAST_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfLastSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfLastSeason(endOfDay);
                break;
            case THIS_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfSeason(endOfDay);
                break;
            case NEXT_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfNextSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfNextSeason(endOfDay);
                break;
            case LAST_YEAR:
                startTimestamp = DateTimeUtil.getFirstDateOfPreviousYear();
                endTimestamp = DateTimeUtil.getFirstDateOfYear();
                break;
            case THIS_YEAR:
                startTimestamp = DateTimeUtil.getFirstDateOfYear();
                endTimestamp = DateTimeUtil.getLastDateOfYear();
                break;
            case NEXT_YEAR:
                startTimestamp = DateTimeUtil.getLastDateOfYear();
                endTimestamp = DateTimeUtil.getLastDateOfNextYear();
                break;
            default:
                break;
        }
        result.put("startTimestamp", startTimestamp);
        result.put("endTimestamp", endTimestamp);
        return result;
    }

    /**
     * 处理筛选动态值
     * @param DateType 日期类型
     * @param DateWay 时间类型
     * @param interval 间隔
     * @param isStart 开始or结束时间
     * @author xinpeng.jiang
     * @date 2021/10/13 11:29
     * @version 1.0
     */
    private static Long handleDynamicDate(Integer DateType, Integer DateWay, Integer interval, boolean isStart) {
        long date;
        // 取一天的开始或结束时间
        if (isStart) {
            date = DateTimeUtil.getStartOfDay(DateUtil.getNow());
        } else {
            date = DateTimeUtil.getEndOfDay(DateUtil.getNow());
        }
        
        if (Objects.equals(DateWay, DateWayEnum.BEFORE.getCode())) {
            // 过去的间隔要取反
            interval = -interval;
            return getTimestampByDateType(DateType, interval, date);
        }
        if (Objects.equals(DateWay, DateWayEnum.NOW.getCode())) {
            return date;
        }
        if (Objects.equals(DateWay, DateWayEnum.FEATURE.getCode())) {
            return getTimestampByDateType(DateType, interval, date);
        }
        
        return null;
    }

    /**
     * 根据日期类型获取差值时间戳
     * @param DateType 日期类型
     * @param interval 间隔
     * @param date 秒级时间戳
     * @return java.lang.Integer
     * @author xinpeng.jiang
     * @date 2021/10/13 13:45
     * @version 1.0
     */
    private static Long getTimestampByDateType(Integer DateType, Integer interval, long date) {
        Long timestamp = null;
        DateTypeEnum dateTypeEnum = DateTypeEnum.getByCode(DateType);
        switch (dateTypeEnum) {
            case DAY:
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.DATE);
                break;
            case WEEK:
                interval = interval * 7;
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.DATE);
                break;
            case MONTH:
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.MONTH);
                break;
            default:
                break;
        }
        return timestamp;
    }

    public static Map<String, ConditionsContainerExt> parseCustomCondition(JSONArray conditionJson, JSONObject formIdAttr) {
        Map<String, ConditionsContainerExt> map = new HashMap<>(16);
        if (CollectionsUtil.isNotEmpty(conditionJson)) {
            for (int i = 0; i < conditionJson.size(); i++) {
                JSONObject filterJson = (JSONObject) conditionJson.get(i);
                Long formId = filterJson.getLong("formId");
                ConditionsContainerExt condition = JSONObject.parseObject(filterJson.toJSONString(), ConditionsContainerExt.class);
                if (!ConditionEnum.EMPTY.getSymbol().equals(condition.getSymbol()) && !ConditionEnum.NOEMPTY.getSymbol().equals(condition.getSymbol())) {
                    if (condition.getValue() != null && condition.getValue().size() == 0) {
                        continue;
                    }
                }
                Integer fieldType = condition.getFieldType();
                String attr = condition.getAttr();
                if(setInData(fieldType) && formIdAttr == null){
                    attr = "data."+attr;
                }else{
                    attr = attr;
                }
                condition.setAttr(attr);
                map.put(attr, condition);
            }
        }
        return map;
    }

    /**
     * 自定义图表条件语句组装(筛选,穿透)
     * @param boolQueryBuilder ES查询
     * @param conditionEnum    筛选类型
     * @param condition        筛选详情
     * @param businessType     业务code
     */
    private static void conditionSymbolChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum,
                                              ConditionsEntityExt condition, boolean isTeam, boolean isPublicFlag, boolean isSingle, Integer businessType) {
        //如果有地址类型的筛选需要特殊拼ES 查询
//        splitAddressCondition(boolQueryBuilder, condition);
        subFormParseValue(condition);
        //subAttr不为空为子表单字段 且单表情况下
        if (Objects.nonNull(condition.getSubAttr()) && isSingle) {
            subFormConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);
        } else if (FieldTypeEnum.OWNERID.getType().equals(condition.getFieldType())) {
            teamConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition, isTeam, 1, isPublicFlag, isSingle, businessType);
        } else if (FieldTypeEnum.COUSERID.getType().equals(condition.getFieldType())) {
            teamConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition, isTeam, 0, false, isSingle, businessType);
        } else if (FieldTypeEnum.BIRTHDAY.getType().equals(condition.getFieldType())) {
            conditionBirthday(boolQueryBuilder, (int) condition.getValue().get(0), null);
        } else if (FieldTypeEnum.ADDRESS.getType().equals(condition.getFieldType())) {
            biAddressConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);
        } else {
            commonConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);
        }
    }

    /**
     * 公用解析（特殊的请单独写）
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param condition
     */
    public static void commonConditionSymbolChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        switch (conditionEnum){
            case EQUAL :
                if (condition.getValue().size() == 1) {
                    Object value = condition.getValue().get(0);
                    if (Objects.equals(FieldTypeEnum.ADDRESS.getType(), condition.getFieldType())
                            || Objects.equals(FieldTypeEnum.LOCATION.getType(), condition.getFieldType())) {
                        biAddressConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);
//                        String data = attr + StringConstant.POINT;
//                        String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
//                        Map<String, Objects> addressJson = (Map)  condition.getValue().get(0);
//                        boolQueryBuilder.filter(termQuery(data + BusinessConstant.CITY + keyword, addressJson.get(BusinessConstant.CITY)));
//                        boolQueryBuilder.filter(termQuery(data + BusinessConstant.DISTRICT + keyword, addressJson.get(BusinessConstant.DISTRICT)));
//                        boolQueryBuilder.filter(termQuery(data + BusinessConstant.ADDRESS + keyword, addressJson.get(BusinessConstant.ADDRESS)));
                    } else if (Objects.equals(FieldTypeEnum.LINK_DATA_MULTI.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.COMBO_CHECK.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.CHECKBOX_GROUP.getType(), condition.getFieldType())
                            || Objects.equals(FieldTypeEnum.USER_GROUP.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.DEPT_GROUP.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.LABEL.getType(), condition.getFieldType())) {
                        // 多选框只有一个值时
                        String key = attr + StringConstant.POINT + StringConstant.KEY_WORD;
                        BoolQueryBuilder multipleBool = boolQuery();
                        multipleBool.should(termsQuery(key, value));
                        multipleBool.minimumShouldMatch(condition.getValue().size());
                        boolQueryBuilder.filter(multipleBool);
                        Script script = new Script("doc['"+key+"'].length == " + condition.getValue().size());
                        boolQueryBuilder.filter(scriptQuery(script));
                    } else if (value instanceof List) {
                       List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
                       String key = attr + StringConstant.POINT + StringConstant.KEY_WORD;
                       BoolQueryBuilder multipleBool = boolQuery();
                       for (Object object : list) {
                           multipleBool.should(termsQuery(key, object));
                       }
                       multipleBool.minimumShouldMatch(condition.getValue().size());
                       boolQueryBuilder.filter(multipleBool);
                       Script script = new Script("doc['"+key+"'].length == " + list.size());
                       boolQueryBuilder.filter(scriptQuery(script));
                   } else if (Objects.equals(FieldTypeEnum.SWITCH.getType(), condition.getFieldType())) {
                        attr = addKeyWord(condition, attr);
                        if (Objects.equals(value.toString(), "0")) {
                            BoolQueryBuilder boolQuery = boolQuery();
                            boolQuery.should(boolQuery().filter(termQuery(attr, 0)));
                            boolQuery.should(boolQuery().mustNot(existsQuery(attr.replace(".keyword", ""))));
                            boolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                            boolQueryBuilder.filter(boolQuery);
                        } else {
                            boolQueryBuilder.filter(termQuery(attr,value));
                        }
                    } else {
                        FieldTypeEnum dateFieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                        if (Objects.nonNull(dateFieldTypeEnum) && Objects.equals(dateFieldTypeEnum.getEsalias(), FieldTypeEnum.DATETIME.getEsalias())) {
                            // 日期字段的相等需要按照范围处理
                            Long conditionValue = Long.valueOf(Objects.toString(value));
                            if (Objects.equals(condition.getDateType(), DateTimeEnum.TIME.getType())) {
                                Long startOfDay = DateTimeUtil.getStartOfDay(conditionValue);
                                Long endOfDay = DateTimeUtil.getEndOfDay(conditionValue);
                                boolQueryBuilder.filter(rangeQuery(attr).gte(startOfDay).lte(endOfDay));
                            } else if (Objects.equals(condition.getDateType(), DateTimeEnum.DATETIME.getType())) {
                                Long startOfMinute = DateTimeUtil.getStartOfMinute(conditionValue);
                                Long endOfMinute = DateTimeUtil.getEndOfMinute(conditionValue);
                                boolQueryBuilder.filter(rangeQuery(attr).gte(startOfMinute).lte(endOfMinute));
                            } else {
                                // 标准模式的公海分组的日期【等于】筛选会走这里
                                attr = addKeyWord(condition, attr);
                                boolQueryBuilder.filter(termQuery(attr, condition.getValue().get(0)));
                            }
                        } else {
                            // 单行文本等的想等
                            attr = addKeyWord(condition, attr);
                            boolQueryBuilder.filter(termQuery(attr, condition.getValue().get(0)));
                        }
                    }
                } else {
                    List<Object> value = condition.getValue();
                    if (CollectionsUtil.isNotEmpty(value)) {
                        if (Objects.equals(FieldTypeEnum.ADDRESS.getType(), condition.getFieldType())
                            || Objects.equals(FieldTypeEnum.LOCATION.getType(), condition.getFieldType())) {
                            biAddressConditionSymbolChoose(boolQueryBuilder, conditionEnum, condition);
                        } else if (Objects.equals(FieldTypeEnum.AREA.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.PURCHASEABLE_GOODS.getType(), condition.getFieldType())) {
                            // 这两个字段需要回显下级，特殊处理
                            String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
                            attr = attr + keyword;
                            boolQueryBuilder.filter(termsQuery(attr, value));
                        } else {
                            // 多选的情况下的相等
                            String key = attr + StringConstant.POINT + StringConstant.KEY_WORD;
                            BoolQueryBuilder multipleBool = boolQuery();
                            for (Object valueItem : condition.getValue()) {
                                multipleBool.should(termsQuery(key, valueItem));
                            }
                            multipleBool.minimumShouldMatch(condition.getValue().size());
                            boolQueryBuilder.filter(multipleBool);
                            Script script = new Script("doc['" + key + "'].length == " + condition.getValue().size());
                            boolQueryBuilder.filter(scriptQuery(script));
                        }
                    }
                }
                break;
            case NOEQUAL:
                FieldTypeEnum attrFieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                if (Objects.nonNull(attrFieldTypeEnum) && Objects.equals(attrFieldTypeEnum.getEsalias(), FieldTypeEnum.DATETIME.getEsalias()) && condition.getValue().size() == 1) {
                    Object value = condition.getValue().get(0);
                    Long conditionValue = Long.valueOf(Objects.toString(value));
                    // 日期字段的不相等需要按照范围处理
                    if (Objects.equals(condition.getDateType(), DateTimeEnum.TIME.getType())) {
                        Long startOfDay = DateTimeUtil.getStartOfDay(conditionValue);
                        Long endOfDay = DateTimeUtil.getEndOfDay(conditionValue);
                        BoolQueryBuilder multipleBool = boolQuery();
                        multipleBool.should(boolQuery().mustNot(existsQuery(attr)));
                        multipleBool.should(rangeQuery(attr).lt(startOfDay));
                        multipleBool.should(rangeQuery(attr).gt(endOfDay));
                        multipleBool.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                        boolQueryBuilder.filter(multipleBool);
                    } else if (Objects.equals(condition.getDateType(), DateTimeEnum.DATETIME.getType())) {
                        Long startOfMinute = DateTimeUtil.getStartOfMinute(conditionValue);
                        Long endOfMinute = DateTimeUtil.getEndOfMinute(conditionValue);
                        BoolQueryBuilder multipleBool = boolQuery();
                        multipleBool.should(boolQuery().mustNot(existsQuery(attr)));
                        //TODO  待测试
                        multipleBool.should(rangeQuery(attr).lt(startOfMinute));
                        multipleBool.should(rangeQuery(attr).gt(endOfMinute));
                        multipleBool.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                        boolQueryBuilder.filter(multipleBool);
                    } else {
                        // 标准模式的公海分组的日期【不等于】筛选会走这里
                        attr = addKeyWord(condition, attr);
                        boolQueryBuilder.mustNot(termQuery(attr, condition.getValue().get(0)));
                    }
                } else {
                    //TODO
                    attr = addKeyWord(condition, attr);
                    boolQueryBuilder.mustNot(termQuery(attr, condition.getValue().get(0)));
                }
                break;
            case EMPTY:
                attr = addKeyWord(condition,attr);
                BoolQueryBuilder boolQuery = boolQuery();
                FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                if (FieldTypeEnum.DATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.STAR.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.DEPARTMENTID.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ADDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.LINK_DATA.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ENDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.CLOSETIME.getType().equals(condition.getFieldType())) {
                    boolQuery.should(boolQuery().filter(termQuery(attr,0)));
                }else if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.UPLOAD.getEsalias())){
                    boolQuery.should(boolQuery().filter(termQuery(attr, "")));
                }else if (!FieldTypeEnum.NUM.getEsalias().equals(fieldTypeEnum.getEsalias()) && !FieldTypeEnum.STAGE_RATIO.getEsalias().equals(fieldTypeEnum.getEsalias())){
                    boolQuery.should(boolQuery().filter(termQuery(attr, "")));
                }
                //空数组也只需这个
                // exists不需要添加keyword
                boolQuery.should(boolQuery().mustNot(existsQuery(attr.replace(".keyword", ""))));
                boolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                // must有性能问题，且没必要，改为filter
                boolQueryBuilder.filter(boolQuery);
                break;
            case NOEMPTY:
                attr = addKeyWord(condition,attr);
                fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                // exists不需要添加keyword
                boolQueryBuilder.filter(existsQuery(attr.replace(".keyword", "")));
                if (FieldTypeEnum.DATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.STAR.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.DEPARTMENTID.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ADDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.LINK_DATA.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ENDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.CLOSETIME.getType().equals(condition.getFieldType())) {
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,0)));
                }else if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.UPLOAD.getEsalias())){
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,"")));
                }else if ( fieldTypeEnum.getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())) {
                    attr = attr.replace(".keyword", "");
                    String provinceAttr = attr + StringConstant.POINT + PaasConstant.PROVINCE + ".keyword";
                    String cityAttr = attr + StringConstant.POINT + PaasConstant.CITY + ".keyword";
                    String districtAttr = attr + StringConstant.POINT + PaasConstant.DISTRICT + ".keyword";
                    String addressAttr = attr + StringConstant.POINT + PaasConstant.ADDRESS + ".keyword";
                    List<String> attrList = Arrays.asList(provinceAttr,cityAttr,districtAttr,addressAttr);
                    BoolQueryBuilder addressCondition = boolQuery();
                    for (String conditionsEntityExtList : attrList) {
                        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                        innerBoolQueryBuilder.filter(boolQuery().mustNot(termQuery(conditionsEntityExtList,"")));
                        addressCondition.should(innerBoolQueryBuilder);
                    }
                    addressCondition.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                    boolQueryBuilder.filter(addressCondition);
                } else if (!FieldTypeEnum.NUM.getEsalias().equals(fieldTypeEnum.getEsalias()) && !FieldTypeEnum.STAGE_RATIO.getEsalias().equals(fieldTypeEnum.getEsalias())){
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,"")));
                }
                break;
            case INCLUDE:
                attr = addKeyWordForIn(condition, attr);
                Set<Object> valueSet = new HashSet<>();
                for (Object obj : condition.getValue()){
                    if (Objects.nonNull(obj)) {
                        valueSet.add(obj);
                    }
                }
                if (!valueSet.isEmpty()) {
                    boolQueryBuilder.filter(termsQuery(attr, valueSet));
                }
                break;
            case LIKE:
                fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                if ( fieldTypeEnum.getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())) {
                    String provinceAttr = attr + StringConstant.POINT + PaasConstant.PROVINCE;
                    String cityAttr = attr + StringConstant.POINT + PaasConstant.CITY;
                    String districtAttr = attr + StringConstant.POINT + PaasConstant.DISTRICT;
                    String addressAttr = attr + StringConstant.POINT + PaasConstant.ADDRESS;
                    List<String> attrList = Arrays.asList(provinceAttr,cityAttr,districtAttr,addressAttr);
                    BoolQueryBuilder addressCondition = boolQuery();
                    for (String conditionsEntityExtList : attrList) {
                        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                        innerBoolQueryBuilder.filter(matchPhraseQuery(conditionsEntityExtList, condition.getValue().get(0)));
                        addressCondition.should(innerBoolQueryBuilder);
                    }
                    addressCondition.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                    boolQueryBuilder.filter(addressCondition);
                }else {
                    boolQueryBuilder.filter(matchPhraseQuery(attr, condition.getValue().get(0)));
                }

                break;
            case NOLIKE:
                boolQueryBuilder.filter(boolQuery().mustNot(matchPhraseQuery(attr, condition.getValue().get(0))));
                break;
            case ALLINCLUDE:
                attr = addKeyWordForIn(condition, attr);
                BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
                for (Object obj : condition.getValue()){
                    innerBoolQueryBuilder.should(termsQuery(attr, obj));
                }
                innerBoolQueryBuilder.minimumShouldMatch(condition.getValue().size());
                boolQueryBuilder.filter(innerBoolQueryBuilder);
                break;
            case IN:
                attr = addKeyWordForIn(condition, attr);
                boolQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                break;
            case NOIN:
                attr = addKeyWordForIn(condition, attr);
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(attr, condition.getValue())));
                break;
            case GREATEREQUAL:
                if (Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty()){
                    return;
                }
                boolQueryBuilder.filter(rangeQuery(attr).gte(condition.getValue().get(0)));
                break;
            case GREATERTHAN:
                if (Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty()){
                    return;
                }
                Object value = condition.getValue().get(0);
                if (FieldTypeEnum.numFieldType(condition.getFieldType()) && RegexUtil.isNumber(value.toString())) {
                    if (value.toString().contains(".")) {
                        value = Double.valueOf(value.toString());
                    } else {
                        value = Long.valueOf(value.toString());
                    }
                    boolQueryBuilder.filter(rangeQuery(attr).gt(value));
                } else {
                    Long time = Long.valueOf(condition.getValue().get(0).toString());
                    boolQueryBuilder.filter(rangeQuery(attr).gt(time));
                }

                break;
            case LESSEQUAL:
                if (Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty()){
                    return;
                }
                Object lessValue = condition.getValue().get(0);
                if (FieldTypeEnum.numFieldType(condition.getFieldType()) && RegexUtil.isNumber(lessValue.toString())) {
                    if (lessValue.toString().contains(".")) {
                        lessValue = Double.valueOf(lessValue.toString());
                    } else {
                        lessValue = Long.valueOf(lessValue.toString());
                    }
                    boolQueryBuilder.filter(rangeQuery(attr).lte(lessValue));
                } else {
                    Long time = Long.valueOf(condition.getValue().get(0).toString());
                    boolQueryBuilder.filter(rangeQuery(attr).lte(time));
                }
                break;
            case LESSTHAN:
                if (Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty()){
                    return;
                }
                boolQueryBuilder.filter(rangeQuery(attr).lt(condition.getValue().get(0)));
                break;
            case RANGE:
            case DYNAMIC:
                if ((Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty())
                        || (Objects.isNull(condition.getValue().get(1)) || condition.getValue().get(1).toString().isEmpty())){
                    return;
                }
                boolQueryBuilder.filter(rangeQuery(attr).gte(condition.getValue().get(0)).lt(condition.getValue().get(1)));
                break;
            case NORANGE:
                if ((Objects.isNull(condition.getValue().get(0)) || condition.getValue().get(0).toString().isEmpty())
                        || (Objects.isNull(condition.getValue().get(1)) || condition.getValue().get(1).toString().isEmpty())){
                    return;
                }
                boolQueryBuilder.filter(rangeQuery(attr).lt(condition.getValue().get(0)).gte(condition.getValue().get(1)));
                break;
            default:
                break;
        }
    }

    /**
     * 经销商管理》筛选项解析
     * @param boolQueryBuilder
     * @param conditionEnum
     * @param condition
     * @author weiming
     */
    public static void symbolChoose4Distributor(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        switch (conditionEnum){
            case EQUAL :
                if (condition.getValue().size() == 1) {
                    Object value = condition.getValue().get(0);
                    // 单行文本等的想等
                    attr = addKeyWord(condition, attr);
                    boolQueryBuilder.filter(termQuery(attr,condition.getValue().get(0)));
                } else {
                    List<Object> value = condition.getValue();
                    if (Objects.equals(FieldTypeEnum.AREA.getType(), condition.getFieldType()) || Objects.equals(FieldTypeEnum.PURCHASEABLE_GOODS.getType(), condition.getFieldType())) {
                        String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
                        attr = attr + keyword;
                        boolQueryBuilder.filter(termsQuery(attr, value));
                    }
                }
                break;
            case NOEQUAL:
                //TODO
                attr = addKeyWord(condition, attr);
                boolQueryBuilder.mustNot(termQuery(attr, condition.getValue().get(0)));
                break;
            case EMPTY:
                attr = addKeyWord(condition,attr);
                BoolQueryBuilder boolQuery = boolQuery();
                FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                if (FieldTypeEnum.DATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.STAR.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.DEPARTMENTID.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ADDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.LINK_DATA.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())){
                    boolQuery.should(boolQuery().filter(termQuery(attr,0)));
                }else if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.UPLOAD.getEsalias())){
                    boolQuery.should(boolQuery().filter(termQuery(attr, "")));
                }else if (!FieldTypeEnum.NUM.getEsalias().equals(fieldTypeEnum.getEsalias()) && !FieldTypeEnum.STAGE_RATIO.getEsalias().equals(fieldTypeEnum.getEsalias())){
                    boolQuery.should(boolQuery().filter(termQuery(attr, "")));
                }
                //空数组也只需这个
                // exists不需要添加keyword
                boolQuery.should(boolQuery().mustNot(existsQuery(attr.replace(".keyword", ""))));
                boolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(boolQuery);
                break;
            case NOEMPTY:
                attr = addKeyWord(condition,attr);
                fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                // exists不需要添加keyword
                boolQueryBuilder.filter(existsQuery(attr.replace(".keyword", "")));
                if (FieldTypeEnum.DATETIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.STAR.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.DEPARTMENTID.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.ADDTIME.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.LINK_DATA.getType().equals(condition.getFieldType())
                        || FieldTypeEnum.UPDATETIME.getType().equals(condition.getFieldType())){
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,0)));
                }else if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())
                        || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.UPLOAD.getEsalias())){
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,"")));
                }else if (!FieldTypeEnum.NUM.getEsalias().equals(fieldTypeEnum.getEsalias()) && !FieldTypeEnum.STAGE_RATIO.getEsalias().equals(fieldTypeEnum.getEsalias())){
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr,"")));
                }
                break;
            case INCLUDE:
                attr = addKeyWordForIn(condition, attr);
                Set<Object> valueSet = new HashSet<>();
                for (Object obj : condition.getValue()){
                    if (Objects.nonNull(obj)) {
                        valueSet.add(obj);
                    }
                }
                if (!valueSet.isEmpty()) {
                    boolQueryBuilder.filter(termsQuery(attr, valueSet));
                }
                break;
            case IN:
                attr = addKeyWordForIn(condition, attr);
                boolQueryBuilder.filter(termsQuery(attr, condition.getValue()));
                break;
            case NOIN:
                attr = addKeyWordForIn(condition, attr);
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(attr, condition.getValue())));
                break;
            default:
                break;
        }
    }

    private static String addKeyWordForIn(ConditionsEntityExt condition, String attr) {
        if (attr.contains("array_") && !attr.contains(".keyword")) {
            String symbol = condition.getSymbol();
            if (Objects.equals(symbol, ConditionEnum.INCLUDE.getSymbol()) || Objects.equals(symbol, ConditionEnum.IN.getSymbol()) || Objects.equals(symbol, ConditionEnum.ALLINCLUDE.getSymbol()) || Objects.equals(symbol, ConditionEnum.NOIN.getSymbol())) {
                return attr + ".keyword";
            }
        }
        if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.USER.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.USER_GROUP.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.COUSERID.getEsalias())) {
            attr = attr + ".keyword";
        }
        return attr;
    }

    public static void subFormParseValue(ConditionsEntityExt condition) {
        List<Object> values = condition.getValue();
        List<Object> list = new ArrayList<>();
        Integer fieldType = condition.getFieldType();
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldType);
        if (condition.getPenetrateFlag() != null && condition.getPenetrateFlag() == 1) {
            Object value;
            if (CollectionsUtil.isEmpty(values)) {
                value = "";
                list.add(value);
                condition.setValue(list);
            }
        } else {
            if (fieldTypeEnum != null) {
                switch (fieldTypeEnum) {
                    case USER:
                    case CREATORID:
                    case OWNERID:
                    case COUSERID:
                    case USER_GROUP:
                        if (CollectionsUtil.isNotEmpty(values)) {
                            for (Object obj : values) {
                                if (obj instanceof String) {
                                    list.add(obj);
                                } else if (obj instanceof JSONObject) {
                                    JSONObject jsonObject = (JSONObject) obj;
                                    String userId = jsonObject.getString(ParameterConstant.USER_ID);
                                    list.add(userId);
                                }
                            }
                        }
                        condition.setValue(list);
                        break;
                    case DEPT:
                    case DEPT_GROUP:
                    case DEPARTMENTID:
                        if (CollectionsUtil.isNotEmpty(values)) {
                            for (Object obj : values) {
                                if (obj instanceof String || obj instanceof Integer || obj instanceof Long) {
                                    list.add(obj);
                                } else if (obj instanceof JSONObject) {
                                    JSONObject jsonObject = (JSONObject) obj;
                                    String userId = jsonObject.getString("id");
                                    list.add(userId);
                                }
                            }
                        }
                        condition.setValue(list);
                        break;
                    case CATEGORY_ID:
                        if (CollectionsUtil.isNotEmpty(values)) {
                            for (Object obj : values) {
                                if (obj instanceof Integer){
                                    list.add(obj);
                                }else if (obj instanceof JSONObject){
                                    JSONObject jsonObject = (JSONObject) obj;
                                    Integer categoryId = jsonObject.getInteger("id");
                                    list.add(categoryId);
                                }
                            }
                        }
                        condition.setValue(list);
                        break;
                    case CONTACT_NUMBER:
                        condition.setAttr(condition.getAttr() + StringConstant.POINT + StringConstant.PHONE_TEL_ATTR);
                        break;
                    case ADDRESS:
                        //地址特殊处理
                        String attr;
                        String[] attrs = condition.getAttr().split("\\.");
                        if (attrs.length > 0) {
                            attr = attrs[attrs.length - 1];
                            if (AddressEnum.getByAlias(attr) != null) {
                                Object value = null;
                                if (AddressEnum.CITY.equals(AddressEnum.getByAlias(attr))) {
                                    value = condition.getValue().get(1);
                                } else if (AddressEnum.DISTRICT.equals(AddressEnum.getByAlias(attr))) {
                                    value = condition.getValue().get(2);
                                }
                                if (value != null) {
                                    List valueList = new ArrayList();
                                    valueList.add(value);
                                    condition.setValue(valueList);
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }

    public static void splitAddressCondition(BoolQueryBuilder boolQueryBuilder, ConditionsEntityExt condition) {
        if (FieldTypeEnum.ADDRESS.equals(FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()))) {
            String attr;
            String preAttr;
            String[] attrs = condition.getAttr().split("\\.");
            if (attrs.length > 0) {
                attr = attrs[attrs.length - 1];
                int lastIndex = condition.getAttr().lastIndexOf(".");
                preAttr = condition.getAttr().substring(0, lastIndex + 1);
                StringBuilder stringBuilder = new StringBuilder();
                if (AddressEnum.getByAlias(attr) != null) {
                    stringBuilder.append(preAttr);
                    stringBuilder.append(AddressEnum.PROVINCE.getAlias());
                    if (AddressEnum.CITY.equals(AddressEnum.getByAlias(attr))) {
                        int size = 2;
                        if (condition.getValue().size() >= size) {
                            if (ConditionEnum.EQUAL.equals(ConditionEnum.getConditionEnum(condition.getSymbol()))) {
                                stringBuilder.append(".keyword");
                                boolQueryBuilder.filter(termQuery(stringBuilder.toString(), condition.getValue().get(0)));
                            } else if (ConditionEnum.LIKE.equals(ConditionEnum.getConditionEnum(condition.getSymbol()))) {
                                boolQueryBuilder.filter(matchPhraseQuery(stringBuilder.toString(), condition.getValue().get(0)));
                            }
                        }
                    } else if (AddressEnum.DISTRICT.equals(AddressEnum.getByAlias(attr))) {
                        int size = 3;
                        if (condition.getValue().size() >= size) {
                            if (ConditionEnum.EQUAL.equals(ConditionEnum.getConditionEnum(condition.getSymbol()))) {
                                stringBuilder.append(".keyword");
                                boolQueryBuilder.filter(termQuery(stringBuilder.toString(), condition.getValue().get(0)));
                                stringBuilder.delete(0, stringBuilder.length());
                                stringBuilder.append(preAttr);
                                stringBuilder.append(AddressEnum.CITY.getAlias());
                                stringBuilder.append(".keyword");
                                boolQueryBuilder.filter(termQuery(stringBuilder.toString(), condition.getValue().get(1)));
                            } else if (ConditionEnum.LIKE.equals(ConditionEnum.getConditionEnum(condition.getSymbol()))) {
                                boolQueryBuilder.filter(matchPhraseQuery(stringBuilder.toString(), condition.getValue().get(0)));
                                stringBuilder.delete(0, stringBuilder.length());
                                stringBuilder.append(preAttr);
                                stringBuilder.append(AddressEnum.CITY.getAlias());
                                boolQueryBuilder.filter(matchPhraseQuery(stringBuilder.toString(), condition.getValue().get(1)));
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 设置 字段是否在data中
     */
    public static boolean setInData(Integer type) {
        FieldTypeEnum fieldType = FieldTypeEnum.getFieldTypeEnum(type);
        if (fieldType != null) {
            if (BelongEnum.SYSTEM.getAlias().equals(fieldType.getBelong()) || BelongEnum.STOCK.getAlias().equals(fieldType.getBelong()) || BelongEnum.WARNING.getAlias().equals(fieldType.getBelong()) || BelongEnum.BATCH.getAlias().equals(fieldType.getBelong())) {
                return false;
            } else {
                return true;
            }
        } else {
            //TODO  异常抛出
        }
        return true;
    }

    /**
     * 特殊的业务、数据全在data外
     *
     * @param businessType
     * @param fieldType
     * @return
     */
    public static boolean specialOutData(Integer businessType, Integer fieldType){
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode(), businessType)
                && !Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldType)) {
            return true;
        }
        return false;
    }

    /**
     * 目前只有工单2.0有这个特殊逻辑,就先这么写了
     *
     * @param businessType
     * @return
     */
    public static boolean isWorkOrderV2CustomChart(Integer businessType){
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode(), businessType)){
            return true;
        }
        return false;
    }

    /**
     * 解析es查询脚本
     * @param esScriptPojo es查询脚本DTO
     */
    public static void parseEsScript(EsScriptConditionPojo esScriptPojo, BoolQueryBuilder boolQueryBuilder) throws XbbException {
        // 获取参数
        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
        List<EsScriptPojo> esScriptList = esScriptPojo.getEsScriptList();
        Integer relCode = esScriptPojo.getRelCode();
        if (Objects.nonNull(esScriptList) && !esScriptList.isEmpty()) {
            for (EsScriptPojo item : esScriptList) {
                EnumBase sourceEnum = item.getSourceEnum();
                Class<?> sourceClazz = sourceEnum.t.getClass();
                EnumBase targetEnum = item.getTargetEnum();
                Class<?> targetClazz = targetEnum.t.getClass();
                ConditionEnum conditionEnum = item.getConditionEnum();

                // 校验参数
                String sourceAttr = getScriptStr(item, sourceEnum, sourceClazz);
                String targetAttr = getScriptStr(item, targetEnum, targetClazz);

                String finalStr = "";
                // 拼接脚本
                switch (conditionEnum) {
                    case GREATERTHAN:
                    case GREATEREQUAL:
                        finalStr = sourceAttr + " - " + targetAttr + conditionEnum.getReplaceSymbol() + "0";
                        break;
                    case LESSEQUAL:
                    case LESSTHAN:
                        finalStr = targetAttr + " - " + sourceAttr + conditionEnum.getReplaceSymbol() + "0";
                        break;
                    default:
                        // 其他的条件不允许出现，用别的方法替代
                        // 抛出异常
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
                }
                Script script = new Script(finalStr);
                if (RelTypeEnum.AND.getCode().equals(relCode) || esScriptList.size() == 1) {
                    innerBoolQueryBuilder.filter(scriptQuery(script));
                } else {
                    innerBoolQueryBuilder.should(scriptQuery(script));
                }
            }
            boolQueryBuilder.filter(innerBoolQueryBuilder);
        }
    }

    /**
     * 校验传入参数是否正确，并且拼接es脚本
     *
     * @param esScriptPojo es脚本DTO
     * @param sourceEnum   传入的枚举，有fieldType信息
     * @param sourceClazz  传入的class，反射获取对应属性
     * @author chaoxiong.lei
     * @date 21:41 2019/3/14
     * @since v1.0
     * @return 拼接好的es脚本字符串
     **/
    private static String getScriptStr(EsScriptPojo esScriptPojo, EnumBase sourceEnum, Class<?> sourceClazz) throws XbbException {
        try {
            Method sourceAttrMethod = sourceClazz.getMethod("getAttr");
            Object sourceAttr = sourceAttrMethod.invoke(sourceEnum.t);
            String sourceStr = (String) sourceAttr;

            Method sourceFieldTypeMethod = sourceClazz.getMethod("getFieldType");
            Object sourceFieldType = sourceFieldTypeMethod.invoke(sourceEnum.t);
            Integer sourceField = (Integer) sourceFieldType;

            if (!FieldTypeEnum.numFieldType(sourceField)
                    && !Objects.equals(sourceField, FieldTypeEnum.DATETIME.getType())
                    && !Objects.equals(sourceField, FieldTypeEnum.PRODUCT_STOCK.getType())) {
                // 不是数字类型的，不能比较
                // 抛出异常
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
            }
            if (esScriptPojo.isSourceNeedData()) {
                sourceStr = "data." + sourceStr;
            }
            sourceStr = "doc['" + sourceStr + "'].value";
            return sourceStr;
        } catch (Exception e) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
    }


    private static String addKeyWord(ConditionsEntityExt condition, String attr) {
        if (FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.USER.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.USER_GROUP.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(condition.getFieldType()).getEsalias().equals(FieldTypeEnum.COUSERID.getEsalias())) {
            attr = attr + ".keyword";
        }
        return attr;
    }

    /**
     * 是否要添加keyword
     * @param type 枚举type编码，如text的1
     * @param attr 字段
     * @return
     */
    public static String addKeyWord(Integer type, String attr) {
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(type);
        if (fieldTypeEnum != null) {
            if (fieldTypeEnum.getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                    || fieldTypeEnum.getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())) {
                attr = attr + ".keyword";
            }
        }
        return attr;
    }


    /**
     * 计算数据中时间的值
     * @param condition
     */
    public static void getValueByDate(ConditionsEntityExt condition) throws XbbException {
        boolean isDate = Objects.equals(FieldTypeEnum.DATETIME.getType(), condition.getFieldType())
                || Objects.equals(FieldTypeEnum.ADDTIME.getType(), condition.getFieldType()) ||
                Objects.equals(FieldTypeEnum.UPDATETIME.getType(), condition.getFieldType());
        if (isDate && (condition.getSymbol().equals(ConditionEnum.RANGE.getSymbol()) || Objects.equals(condition.getSymbol(), ConditionEnum.DYNAMIC.getSymbol()))
                && condition.getValue().size() == CONDITION_TIME_LENGTH) {
            condition.setValue(PaasDateUtil.computeTime(condition.getValue()));
        }
    }

    /**
     * 下划线转驼峰
     * @param words
     * @return
     */
    public static String getHumpString(String words) {
        char c;
        StringBuilder sb = new StringBuilder();
        boolean flag = false;
        for (int i = 0; i < words.length(); i++) {
            c = words.charAt(i);

            if (c == "_".charAt(0)) {
                flag = true;
            } else {
                if (flag) {
                    sb.append(Character.toUpperCase(c));
                } else {
                    sb.append(c);
                }
                flag = false;
            }
        }
        return sb.toString();
    }

    /**
     * (驼峰转下划线)
     * 将opportunityNo 转化成opportunity_no 的数据库字段
     * @param words
     * @return
     */
    public static String getDataBaseString(String words) {
        char c;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < words.length(); i++) {
            c = words.charAt(i);
            if (Character.isUpperCase(words.charAt(i))) {
                sb.append('_');
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }


    public static String createGroupAttrValue(int num, List<String> groupList, JSONObject dataObject) {
        String group = "";
        if (groupList != null && groupList.size() > num) {
            if (!StringUtil.isEmpty(groupList.get(num))) {
                group = dataObject.getString(getHumpString(groupList.get(num)));
                if (!StringUtil.isEmpty(group)) {
                    group = replaceSpecialCharacter(group);
                }
            }
        }
        return group;
    }

    /**
     * 过滤斜线、两种换行
     * @param str
     * @return
     * 2017年5月22日下午8:15:13
     * LuJiang
     */
    public static String replaceSpecialCharacter(String str) {
        //对斜线的转义
        str = str.replaceAll("\\\\", "\\\\" + "\\\\");
        str = str.replaceAll("\r\n", "\\\\r\\\\n");
        str = str.replaceAll("\n", "\\\\n");
        //引号
        str = str.replaceAll("\"", "\\\\\"");
        return str;
    }

    /**
     * 设置返回字段
     * @param nativeSearchQueryBuilder
     * @param fieldList
     */
    public static void setFieldList(NativeSearchQueryBuilder nativeSearchQueryBuilder, List<String> fieldList) {
        if (fieldList != null && !fieldList.isEmpty()) {
            fieldList = mergeFieldList(fieldList, NO_DATA_COLUMNS);
            fieldList = new ArrayList<>(fieldList);
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            String[] strings = new String[fieldList.size()];
            nativeSearchQueryBuilder.withFields(fieldList.toArray(strings));
        }
    }

    public static void setFieldList(SearchSourceBuilder sourceBuilder, List<String> fieldList) {
        if (fieldList != null && !fieldList.isEmpty()) {
            fieldList = mergeFieldList(fieldList, NO_DATA_COLUMNS);
            fieldList = new ArrayList<>(fieldList);
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            String[] strings = new String[fieldList.size()];
            sourceBuilder.fetchSource(fieldList.toArray(strings), null);
        }
    }

    public static void setSubFieldList(SearchSourceBuilder sourceBuilder, List<String> fieldList) {
        if (fieldList != null && !fieldList.isEmpty()) {
            fieldList = mergeSubFieldList(fieldList, NO_DATA_SUB_FORM_COLUMNS);
            fieldList = new ArrayList<>(fieldList);
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            String[] strings = new String[fieldList.size()];
            sourceBuilder.fetchSource(fieldList.toArray(strings), null);
        }
    }
    /**
     * 设置查询参数值
     * @param sourceBuilder
     * @param fieldList 需要查询的字段
     * @param businessType 业务类型，主要是为了区分其他业务和工单出库、销售出库，因为后两者的客户电话是subForm_3需要查询主表
     * @return
     */
    public static void setFieldList(SearchSourceBuilder sourceBuilder, List<String> fieldList, Integer businessType) {
        if (fieldList != null && !fieldList.isEmpty()) {
            fieldList = mergeFieldList(fieldList, NO_DATA_COLUMNS, businessType);
            fieldList = new ArrayList<>(fieldList);
            fieldList.add(StringConstant.SAAS_LINK_BUSINESS_ID);
            String[] strings = new String[fieldList.size()];
            sourceBuilder.fetchSource(fieldList.toArray(strings), null);
        }
    }


    /**
     * 设置返回字段，不处理fieldList
     * @param sourceBuilder 查询
     * @param fieldList     要展示的字段
     * @author zcp
     * @date 2019/4/9 20:12
     * @since v1.0
     * @version v1.0
     */
    public static void setFieldListNoMerge(SearchSourceBuilder sourceBuilder, List<String> fieldList) {
        if (fieldList != null && !fieldList.isEmpty()) {
            //限定返回值，只展示某些字段，默认展示全部
            String[] strings = new String[fieldList.size()];
            sourceBuilder.fetchSource(fieldList.toArray(strings), null);
        }
    }
    public static void setFieldListNoMerge(NativeSearchQueryBuilder nativeSearchQueryBuilder, List<String> fieldList) {
        if (fieldList != null && !fieldList.isEmpty()) {
            //限定返回值，只展示某些字段，默认展示全部
            String[] strings = new String[fieldList.size()];
            nativeSearchQueryBuilder.withFields(fieldList.toArray(strings));
        }
    }

    /**
     * 设置页码
     * @param nativeSearchQueryBuilder
     * @param page
     * @param pageSize
     * @return
     */
    public static int setPage(NativeSearchQueryBuilder nativeSearchQueryBuilder, Integer page, Integer pageSize) {
        page = page == null ? 1 : page;
        pageSize = pageSize == null ? 20 : pageSize;
        page = page < 1 ? 1 : page;
        PageRequest pageRequest = PageRequest.of((page - 1), pageSize);
        nativeSearchQueryBuilder.withPageable(pageRequest);
        return page;
    }

    /**
     * 设置分页
     * @param sourceBuilder
     * @param page 当前页
     * @param pageSize 每页大小
     * @return
     */
    public static PageRequest setPage(SearchSourceBuilder sourceBuilder, Integer page, Integer pageSize) {
        page = page == null ? 1 : page;
        pageSize = pageSize == null ? 20 : pageSize;
        page = page < 1 ? 1 : page;
        int from = (page - 1) * pageSize;
        if (from + pageSize > SizeConstant.PAGE_SIZE) {
            from = 1;
            pageSize = 20;
        }
        sourceBuilder.from(from);
        sourceBuilder.size(pageSize);
        pageSize = pageSize == 0 ? 1 : pageSize;
        PageRequest pageRequest = PageRequest.of((page - 1), pageSize);
        return pageRequest;
    }

    /**
     * 合并返回值
     * @param fieldList
     * @return
     */
    public static List<String> mergeDataIdList(List<String> fieldList) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < fieldList.size(); i++) {
            String field = fieldList.get(i);
            if (field.contains("_")) {
                list.add("data." + field);
            } else {
                list.add(field);
            }
        }
        String[] array = SYSTEM_COLUMNS.split(",");
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
        return list;
    }

    /**
     * 合并返回值
     * @param fieldList
     * @return
     */
    public static List<String> mergeFieldList(List<String> fieldList, String columus) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < fieldList.size(); i++) {
            String field = fieldList.get(i);
            if (field.contains("_") && !field.contains("data")) {
                if (field.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                   String[] attr = field.split("\\.");
                   String[] subAttrArray = attr[0].split("_");
                   if (Integer.valueOf(subAttrArray[1]) < 3) {
                       list.add("data." + field);
                   }
                } else {
                    list.add("data." + field);
                }
            } else {
                list.add(field);
            }
        }
        String[] array = columus.split(",");
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
        return list;
    }

    /**
     * 合并返回值
     * @param fieldList 需要查询的字段
     * @param columus 默认规定的字段，一般是系统字段
     * @param businessType 业务类型，主要是为了区分其他业务和工单出库、销售出库，因为后两者的客户电话是subForm_3需要查询主表
     * @return
     */
    public static List<String> mergeFieldList(List<String> fieldList, String columus, Integer businessType) {
        List<String> list = new ArrayList<>();
        List<Integer> blockList = Arrays.asList(XbbRefTypeEnum.WORK_ORDER_OUTSTOCK.getCode(), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode());
        for (int i = 0; i < fieldList.size(); i++) {
            String field = fieldList.get(i);
            if (field.contains("_")) {
                if (field.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                    String[] attr = field.split("\\.");
                    String[] subAttrArray = attr[0].split("_");
                    if (Integer.valueOf(subAttrArray[1]) < 3 && !blockList.contains(businessType)) {
                        list.add("data." + field);
                    } else if (blockList.contains(businessType) && Integer.valueOf(subAttrArray[1]) == 3) {
                        list.add("data." + field);
                    }
                } else {
                    list.add("data." + field);
                }
            } else {
                list.add(field);
            }
        }
        String[] array = columus.split(",");
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
        return list;
    }

    /**
     * 合并返回值
     * @param fieldList
     * @return
     */
    public static List<String> mergeSubFieldList(List<String> fieldList, String columus) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < fieldList.size(); i++) {
            String field = fieldList.get(i);
            if (field.contains("_")) {
                list.add("data." + field);
            } else {
                list.add(field);
            }
        }
        String[] array = columus.split(",");
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
        return list;
    }

    /**
     * 拼接查询条件
     * @param boolQueryBuilder 查询条件
     * @param object           反射的对象,获取参数的对象
     * @param queryIgnore      是否检查查询忽略标签
     * @throws XbbException
     */
    @Deprecated
    public static void getTermQuery(BoolQueryBuilder boolQueryBuilder, Object object, boolean queryIgnore) throws XbbException {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());

            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                // 过滤class属性
                if ("class".equals(property.getName())) {
                    continue;
                }

                //获得get方法
                Method getMethod = property.getReadMethod();
                //检查查询忽略标签
                if (queryIgnore) {
                    boolean ignore = getMethod.isAnnotationPresent(QueryIgnore.class);
                    if (ignore) {
                        continue;
                    }
                }
                //执行get方法返回一个Object
                Object value = getMethod.invoke(object);
                if (value != null) {
                    if ("corpid".equals(property.getName())) {
                        boolQueryBuilder.filter(termQuery(property.getName() + ".keyword", value));
                    } else {
                        boolQueryBuilder.filter(termQuery(property.getName(), value));
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("拼接查询条件出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }


    public static void getQuery(Object object) throws XbbException {
        Class clazz = object.getClass();
        try {
            Field[] fields = clazz.getDeclaredFields();
            if (fields != null && fields.length > 0) {
                for (Field field : fields) {
                    if (field.getType() != List.class && !"serialVersionUID".equals(field.getName())) {
                        PropertyDescriptor pd = new PropertyDescriptor(field.getName(),
                                clazz);
                        //获得get方法
                        Method getMethod = pd.getReadMethod();
                        boolean ignore = getMethod.isAnnotationPresent(QueryIgnore.class);
                        if (ignore) {
                            continue;
                        }
                        //执行get方法返回一个Object
                        Object value = getMethod.invoke(object);
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("拼接查询条件出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }
    @Deprecated
    public static IndexTypeEnum getIndexTypeEnum(IndexTypeEnum indexTypeEnum, Integer saasMark, Integer businessType) throws XbbException {
        return getIndexTypeEnum(saasMark, businessType);
    }

    @Deprecated
    public static IndexTypeEnum getIndexTypeEnum(Integer saasMark, Integer businessType) throws XbbException {
        IndexTypeEnum indexTypeEnum;
        if (Objects.equals(SaasMarkEnum.PAAS.getCode(), saasMark) && !Objects.equals(businessType, IndexTypeEnum.IDX_SUB_FORM_DATA.getCode())) {
            indexTypeEnum = IndexTypeEnum.IDX_FORM_DATA;
        } else {
            //TODO  后面SAAS可能会有某些特殊字段要单独处理
            if (businessType == null || businessType.equals(0)) {
                LOG.error("businessType为空");
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100130);
            }
            businessType = XbbRefTypeEnum.transferBusinessType2Index(businessType);
            indexTypeEnum = IndexTypeEnum.getByCode(businessType);
        }
        return indexTypeEnum;
    }

    /**
     * 各个业务子表单枚举
     * @return
     * @throws XbbException
     */
    public static IndexTypeEnum getSubFormIndexTypeEnum(IndexTypeEnum indexTypeEnum) throws XbbException {

        return  IndexTypeEnum.getSubEnum(indexTypeEnum);
    }

    /**
     * 拼接字符串
     * @param data 数据更新
     * @return
     */
    public static StringBuilder getBuildString(StringBuilder builder, UpdateDataValueEntity data) {
        builder.append("ctx._source.");
        builder.append(data.getEsKey());
        builder.append("=");
        Object value = data.getValue();
        if (value instanceof String) {
            builder.append("'");
            builder.append(data.getValue());
            builder.append("'");
        } else {
            builder.append(data.getValue());
        }
        builder.append(";");
        return builder;
    }

    public static void main(String[] args) throws Exception {
        FormDataListDTO formDataListDTO = new FormDataListDTO();
        formDataListDTO.setAppId(100L);
        Calendar.getInstance().setTime(new Date());
        System.out.println(LocalDate.of(2019,1,1).with(TemporalAdjusters.lastDayOfYear()).getDayOfYear());
        System.out.println(LocalDate.of(2019,1,1).with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth());
        System.out.println("&67".substring(1));
    }

    /**
     * 拼装conditionExt实体
     *
     * @param attr
     * @param value
     * @param conditionEnum
     * @param fieldType
     * @author chaoxiong.lei
     * @Date 17:18 2019/3/8
     * @since v1.0
     * @return 条件实体
     **/
    public static ConditionsEntityExt packageContions(String attr, List<Object> value, ConditionEnum conditionEnum, Integer fieldType) {
        ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt();
        conditionsEntityExt.setAttr(attr);
        conditionsEntityExt.setValue(value);
        conditionsEntityExt.setSymbol(conditionEnum.getSymbol());
        conditionsEntityExt.setFieldType(fieldType);
        return conditionsEntityExt;
    }

    /**
     * 解析或条件
     * @param boolQueryBuilder
     * @param shouldConditions
     * @param rel
     * @param corpid
     * @param businessType
     * @throws XbbException
     */
    public static void parseShouldCondition(BoolQueryBuilder boolQueryBuilder, List<List<ConditionsEntityExt>> shouldConditions, String rel, String corpid, Integer businessType) throws XbbException {
        if (shouldConditions == null || shouldConditions.isEmpty()) {
            return;
        }
        BoolQueryBuilder condition = boolQuery();
        for (List<ConditionsEntityExt> conditionsEntityExtList : shouldConditions) {
            conditionsEntityExtList.forEach(item -> item.setShouldFlag(true));
            BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
            EsUtil.parseCondition(innerBoolQueryBuilder, conditionsEntityExtList, rel, corpid, businessType);
            condition.should(innerBoolQueryBuilder);
        }
        condition.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        boolQueryBuilder.filter(condition);
    }

    /**
     * 模糊查询参数设置
     * @param saasMark
     * @param nameLike
     * @param businessType
     * @param simple
     * @param boolQueryBuilder
     * @param onlyNameLike     是否有其他的或条件 A or B or C or D 和 (A or B) and (C or D)
     * @param explainMap       paas  确定attr
     */
    public static void setNameLike(Integer saasMark, String nameLike, Integer businessType, Boolean simple, BoolQueryBuilder boolQueryBuilder, boolean onlyNameLike, Map<String, FieldAttrEntity> explainMap, UserVO loginUser) {
        List<String> searchAttrList;
        if (nameLike == null || nameLike.isEmpty()) {
            return;
        }
        boolean isOrder = Objects.equals(businessType, XbbRefTypeEnum.ORDER.getCode());
        if (Objects.equals(saasMark, SaasMarkEnum.SAAS.getCode())) {
            // 经销商与客户的模糊搜索一致，所以不需要新加searchList 如果有不一致的情况 联系我
            businessType = XbbRefTypeEnum.transferBusinessType2Index(businessType);
            searchAttrList = ListSearchEnum.getByBusinessType(businessType, simple);
        } else {
            searchAttrList = paasAttrAssemble(explainMap);
        }
        if (isOrder) {
            searchAttrList.remove("data." + ContractEnum.NAME.getAttr());
        }
        // 如果表单的电话子表单关闭，禁止联系方式模糊查询入口
        if(explainMap != null && Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) && explainMap.containsKey(CustomerManagementEnum.PHONE.getAttr())) {
            FieldAttrEntity fieldAttr = explainMap.get(CustomerManagementEnum.PHONE.getAttr());
            if(Objects.equals(fieldAttr.getIsOpen(), BasicConstant.ZERO) || Objects.equals(fieldAttr.getVisible(), BasicConstant.ZERO)){
                searchAttrList.remove("data." + CustomerManagementEnum.PHONE.getAttr() + "." + ListSearchEnum.CUSTOMER_PHONE.getSubAttr());
            }
        }
        // 如果表单的电话子表单关闭，禁止联系方式模糊查询入口
        if(explainMap != null && Objects.equals(businessType, XbbRefTypeEnum.CLUE.getCode()) && explainMap.containsKey(ClueEnum.PHONE.getAttr())) {
            FieldAttrEntity fieldAttr = explainMap.get(ClueEnum.PHONE.getAttr());
            if(Objects.equals(fieldAttr.getIsOpen(), BasicConstant.ZERO) || Objects.equals(fieldAttr.getVisible(), BasicConstant.ZERO)){
                searchAttrList.remove("data." + ClueEnum.PHONE.getAttr() + "." + ListSearchEnum.CLUE_PHONE.getSubAttr());
            }
        }
        // 如果电话字段开启了电话掩码规则 禁止联系方式模糊查询入口（管理员和老板除外）
        if (isNeedMaskTelephoneNumber(businessType, explainMap, loginUser)) {
            searchAttrList.remove("data." + AllFieldEnum.PHONE.getAttr() + "." + ListSearchEnum.CLUE_PHONE.getSubAttr());
        }

        /*if (onlyNameLike){
            if(CollectionsUtil.isNotEmpty(searchAttrList)){
                for (String attr : searchAttrList){
                 boolQueryBuilder.should(matchPhraseQuery(attr, nameLike));
               }
            }
        }else {*/
        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
        if (CollectionsUtil.isNotEmpty(searchAttrList)) {
            innerBoolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            for (String attr : searchAttrList) {
                innerBoolQueryBuilder.should(matchPhraseQuery(attr, nameLike));
                innerBoolQueryBuilder.should(matchPhraseQuery(attr + StringConstant.POINT + StringConstant.KEY_WORD, nameLike));
            }
        }
        boolQueryBuilder.filter(innerBoolQueryBuilder);
        //}
        //if (!searchAttrList.isEmpty()){
        //    boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        //}
    }

    /**
     * 是否开启电话掩码，开启电话掩码，并且用户角色非管理员或者老板，列表页禁止根据电话号码搜索
     *  影响范围=客户管理、联系人、供应商联系人、市场线索
     * @param businessType
     * @param explainMap
     * @param loginUser
     */
    private static boolean isNeedMaskTelephoneNumber(Integer businessType, Map<String, FieldAttrEntity> explainMap, UserVO loginUser) {
        try {
            if (Objects.nonNull(explainMap)) {
                if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.CLUE.getCode())
                        || (Objects.equals(businessType, XbbRefTypeEnum.CONTACT.getCode())) || Objects.equals(businessType, XbbRefTypeEnum.SUPPLIER_CONTACT.getCode())) {
                    if (explainMap.containsKey(AllFieldEnum.PHONE.getAttr())) {
                        FieldAttrEntity fieldAttrEntity = explainMap.get(AllFieldEnum.PHONE.getAttr());
                        //老板和管理员不受电话掩码影响
                        if (Objects.isNull(loginUser) || loginUser.isAdminOrBoss()) {
                            return false;
                        }
                        SubFormPoJo subForm = fieldAttrEntity.getSubForm();
                        boolean isOpenTelephoneMask = false;
                        List<? extends FieldAttrEntity> items = subForm.getItems();
                        if (CollectionsUtil.isNotEmpty(items)) {
                            for (FieldAttrEntity item : items) {
                                if (Objects.equals(item.getSaasAttr(), ContactEnum.PHONE.getSaasAttr())) {
                                    if (Objects.equals(item.getIsMaskTelephone(), BasicConstant.ONE)) {
                                        isOpenTelephoneMask = true;
                                    }
                                }
                            }
                        }
                        return isOpenTelephoneMask;
                    }
                }
            }
            return false;
        } catch (Exception e) {
            LOG.error("ExplainUtil.isOpenTelephoneMask方法出错", e);
            return false;
        }
    }

    /**
     * paas Attr 组装
     * @param explainMap
     * @return
     */
    public static List<String> paasAttrAssemble(Map<String, FieldAttrEntity> explainMap) {
        List<String> searchAttrList = new ArrayList<>();
        Iterator<Map.Entry<String, FieldAttrEntity>> iterator = explainMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, FieldAttrEntity> entry = iterator.next();
            if (FieldTypeEnum.TEXT.getType().equals(entry.getValue().getFieldType()) || FieldTypeEnum.TEXTAREA.getType().equals(entry.getValue().getFieldType())) {
                searchAttrList.add("data." + entry.getValue().getAttr());
            } else if (FieldTypeEnum.SERIALNO.getType().equals(entry.getValue().getFieldType())) {
                searchAttrList.add(entry.getValue().getAttr());
            }
        }
        return searchAttrList;
    }

    /**
     * 产品模糊查询
     * @param nameLike
     * @param nameLikeIdIn
     * @param boolQueryBuilder
     */
    public static void setProductNameLike(String nameLike, List<Long> nameLikeIdIn, BoolQueryBuilder boolQueryBuilder, boolean onlyNameLike) {
        if (nameLike == null || nameLike.isEmpty()) {
            return;
        }
        List<String> searchAttrList = ListSearchEnum.getByBusinessType(XbbRefTypeEnum.PRODUCT.getCode(), false);
        // 库存查询需要，预警和保质期在前面查过了，去除
        //searchAttrList.remove("data." + ListSearchEnum.PRODUCT_SPECIFICATION.getAttr());
        /*if (onlyNameLike){
            for (String attr : searchAttrList){
                boolQueryBuilder.should(matchPhraseQuery(attr, nameLike));
            }
            if (Objects.nonNull(nameLikeIdIn) && !nameLikeIdIn.isEmpty()){
                boolQueryBuilder.should(termsQuery(FieldTypeEnum.DATAID.getAlias(), nameLikeIdIn));
            }
            if (!searchAttrList.isEmpty()){
                boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            }
        }else {*/
        BoolQueryBuilder innerBoolQueryBuilder = boolQuery();
        for (String attr : searchAttrList) {
            innerBoolQueryBuilder.should(matchPhraseQuery(attr, nameLike));
        }
        if (Objects.nonNull(nameLikeIdIn) && !nameLikeIdIn.isEmpty()) {
            innerBoolQueryBuilder.should(termsQuery(FieldTypeEnum.DATAID.getAlias(), nameLikeIdIn));
        }
        innerBoolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        boolQueryBuilder.filter(innerBoolQueryBuilder);
        //}
//        if (!searchAttrList.isEmpty()){
//            boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
//        }
    }

    /**
     * 团队相关查询处理
     * @param isMain  负责人/协同人标志
     * @param attr    字段名
     * @param objects 查询详细内容值
     * @author zhouwq
     * @date 2019/5/7 9:22
     */
    private static NestedQueryBuilder conditionTeamBuilder(Integer isMain, String attr, List<Object> objects, boolean isPublicFlag) {
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery(attr + StringConstant.POINT + ParameterConstant.IS_MAIN, isMain));
        if (isPublicFlag) {
            teamQueryBuilder.filter(termQuery(attr + StringConstant.POINT + StringConstant.DEL, -1));
        } else {
            teamQueryBuilder.filter(termQuery(attr + StringConstant.POINT + StringConstant.DEL, DelEnum.NORMAL.getDel()));
        }

        List<String> userIds = new ArrayList<>();
        //获取userId 作为子查询的主要查询条件
        for (Object obj : objects) {
            String dataId = "";
            if (obj instanceof String) {
                dataId = String.valueOf(obj);
            } else if (obj instanceof JSONObject) {
                JSONObject jsonObject = (JSONObject) obj;
                dataId = jsonObject.getString(ParameterConstant.USER_ID);
            }
            userIds.add(dataId);
        }
        //TODO  1.考虑 should改为terms   2.全公司筛选场景 不需要判断userID
        teamQueryBuilder.filter(termsQuery(attr + StringConstant.POINT + ParameterConstant.USER_ID + ".keyword", userIds));
//        teamQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        return nestedQuery(attr, teamQueryBuilder, ScoreMode.None);
    }

    /**
     * 团队相关查询处理
     * @param isMain 负责人/协同人标志
     * @param objects 查询详细内容值
     * @author zhouwq
     * @date 2019/5/7 9:22
     */
    private static HasChildQueryBuilder conditionSingleTeamBuilder(Integer isMain, List<Object> objects, boolean isPublicFlag, Integer businessType){
        UserTeamEnum userTeamEnum = UserTeamEnum.getByCode(businessType);
        IndexTypeEnum indexTypeEnum = userTeamEnum.getIndexTypeEnum();
        // 获取字段
        String isMainAttr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, ParameterConstant.IS_MAIN);
        String userIdAttr = SubFormTransferEnum.getEsAttrByIndexTypeAndDbAttr(indexTypeEnum, ParameterConstant.USER_ID);
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery(isMainAttr, isMain));
        if(isPublicFlag){
            teamQueryBuilder.filter(termQuery(StringConstant.DEL, -1));
        }else {
            teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        }

        List<String> userIds = new ArrayList<>();
        //获取userId 作为子查询的主要查询条件
        for(Object obj : objects){
            String dataId = "";
            if (obj instanceof String) {
                dataId = String.valueOf(obj);
            } else if (obj instanceof JSONObject) {
                JSONObject jsonObject = (JSONObject)obj;
                dataId = jsonObject.getString(ParameterConstant.USER_ID);
            }
            userIds.add(dataId);
        }
        teamQueryBuilder.filter(termsQuery(userIdAttr, userIds));
//        teamQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        return JoinQueryBuilders.hasChildQuery("my_team",teamQueryBuilder, ScoreMode.Max);

    }


    /**
     * 团队筛选解析
     * @param boolQueryBuilder es查询api
     * @param conditionEnum    筛选类型
     * @param condition        筛选详情
     * @param isTeam           判断该表单是否走团队逻辑
     * @param isMain           判断是负责人或协同人
     * @param isPublicFlag     是否是公海客户 del = -1
     * @param businessType     业务code
     * @author zhouwq
     * @date 2019/5/7 15:59
     */
    private static void teamConditionSymbolChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition, boolean isTeam,
                                                  Integer isMain, boolean isPublicFlag, boolean isSingle, Integer businessType) {
        String attr = condition.getAttr();
        List<Object> values = condition.getValue();
        switch (conditionEnum) {
            case EQUAL:
            case IN:
            case INCLUDE:
                if (isTeam) {
                    if (isSingle) {
                        boolQueryBuilder.filter(conditionSingleTeamBuilder(isMain, values, isPublicFlag, businessType));
                    } else {
                        boolQueryBuilder.filter(conditionTeamBuilder(isMain, attr, values, isPublicFlag));
                    }
                } else if (Objects.equals(1, isMain)) {
                    attr = addKeyWord(condition, attr);
                    for (Object obj : values) {
                        boolQueryBuilder.should(termsQuery(attr, obj));
                    }
                    boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                }
                break;
            case ALLINCLUDE:
                if (isTeam) {
                    for (Object value : values) {
                        List<Object> newValue = new ArrayList<>();
                        newValue.add(value);
                        if (isSingle) {
                            boolQueryBuilder.must(conditionSingleTeamBuilder(isMain, newValue, false, businessType));
                        } else {
                            boolQueryBuilder.must(conditionTeamBuilder(isMain, attr, newValue, false));
                        }
                    }
                } else if (Objects.equals(1, isMain)) {
                    attr = addKeyWord(condition, attr);
                    for (Object obj : values) {
                        boolQueryBuilder.should(termsQuery(attr, obj));
                    }
                    boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                }
                break;
            case NOEQUAL:
            case NOIN:
                if (isTeam) {
                    if (isSingle) {
                        boolQueryBuilder.mustNot(conditionSingleTeamBuilder(isMain, values, false, businessType));
                    } else {
                        boolQueryBuilder.mustNot(conditionTeamBuilder(isMain, attr, values, false));
                    }
                } else if (Objects.equals(1, isMain)) {
                    attr = addKeyWord(condition, attr);
                    for (Object obj : values) {
                        boolQueryBuilder.mustNot(termsQuery(attr, obj));
                    }
                    boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                }
                break;
            case EMPTY:
                //TODO 为空不为空等确定方案
                break;
            case NOEMPTY:
                break;
            default:
                break;
        }
    }


    /**
     * Description: 地址字段封装到es查询语句(列表，共享权限以及图标搜素使用)
     * @param boolQueryBuilder
	 * @param conditionEnum
	 * @param condition
     * @author 魏荣杰
     * @date 2023/3/31 19:05
     */
    private static void biAddressConditionSymbolChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        List<Object> values = condition.getValue();
        String province = null;
        String city = null;
        String district = null;
        if (values != null) {
            province = values.size() > 0 ? values.get(0).toString() : null;
            city = values.size() > 1 ? values.get(1).toString() : null;
            district = values.size() > 2 ? values.get(2).toString() : null;
        }
        String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
        boolean containsAddress = attr.contains(BusinessConstant.PROVINCE) || attr.contains(BusinessConstant.CITY) || attr.contains(BusinessConstant.DISTRICT);
        switch (conditionEnum) {
            case EQUAL:
                if (province != null) {
                    //兼容穿透查询 或统计图
                    if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                        boolQueryBuilder.filter(termQuery(attr + keyword, province));
                        break;
                    }
                    boolQueryBuilder.filter(termQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE + keyword, province));
                    if (city != null) {
                        boolQueryBuilder.filter(termQuery(attr + StringConstant.POINT + BusinessConstant.CITY + keyword, city));
                        if (district != null) {
                            boolQueryBuilder.filter(termQuery(attr + StringConstant.POINT + BusinessConstant.DISTRICT + keyword, district));
                        }
                    }
                }
                break;
            case NOEQUAL:
                if (province != null) {
                    //兼容穿透查询 或统计图
                    if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                        boolQueryBuilder.mustNot(termQuery(attr + keyword, province));
                        break;
                    }
                    boolQueryBuilder.mustNot(termQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE + keyword, province));
                    if (city != null) {
                        boolQueryBuilder.mustNot(termQuery(attr + StringConstant.POINT + BusinessConstant.CITY + keyword, city));
                        if (district != null) {
                            boolQueryBuilder.mustNot(termQuery(attr + StringConstant.POINT + BusinessConstant.DISTRICT + keyword, district));
                        }
                    }
                }
                break;
            case EMPTY:
                BoolQueryBuilder boolQuery = boolQuery();
                //兼容穿透查询
                if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                    boolQuery.should(boolQuery().filter(termQuery(attr + keyword, "")));
                } else {
                    boolQuery.should(boolQuery().filter(termQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE + keyword, "")));
                }
                boolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(boolQuery);
                break;
            case NOEMPTY:
                if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr + keyword,"")));
                    boolQueryBuilder.filter(boolQuery().must(existsQuery(attr + keyword)));
                } else {
                    boolQueryBuilder.filter(boolQuery().mustNot(termQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE + keyword,"")));
                    boolQueryBuilder.filter(boolQuery().must(existsQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE + keyword)));
                }
                break;
            case LIKE:
                BoolQueryBuilder likeBoolQuery = boolQuery();
                if (province != null) {
                    if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                        likeBoolQuery.should(matchPhraseQuery(attr, province));
                    } else {
                        likeBoolQuery.should(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE, province));
                        likeBoolQuery.should(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.CITY, province));
                        likeBoolQuery.should(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.DISTRICT, province));
                        likeBoolQuery.should(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.ADDRESS, province));
                    }
                }
                likeBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.filter(likeBoolQuery);
                break;
            case NOLIKE:
                BoolQueryBuilder noLikeBoolQuery = boolQuery();
                if (province != null) {
                    if (Objects.equals(condition.getPenetrateFlag(), BasicConstant.ONE) || containsAddress) {
                        noLikeBoolQuery.must(boolQuery().mustNot(matchPhraseQuery(attr, province)));
                    } else {
                        noLikeBoolQuery.must(boolQuery().mustNot(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.PROVINCE, province)));
                        noLikeBoolQuery.must(boolQuery().mustNot(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.CITY, province)));
                        noLikeBoolQuery.must(boolQuery().mustNot(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.DISTRICT, province)));
                        noLikeBoolQuery.must(boolQuery().mustNot(matchPhraseQuery(attr + StringConstant.POINT + BusinessConstant.ADDRESS, province)));
                    }
                }
                boolQueryBuilder.filter(noLikeBoolQuery);
                break;
            default:
                break;
        }
    }

    /**
     * 获取生日时间（阳历、阴历）
     *
     * @param solarTime    阳历起始时间
     * @param intervalTime 时间间隔
     * @param birthdayPojo 存储时间的pojo
     * @author 徐俊杰
     * @date 2019/6/21 18:34
     * @since v1.0
     */
    private static void getBirthdayTime(int solarTime, int intervalTime, BirthdayPojo birthdayPojo) {
        List<String> solarList = birthdayPojo.getSolarList();
        List<String> lunarList = birthdayPojo.getLunarList();
        int lunarTime;
        for (int i = 0; i < intervalTime; i++) {
            if (i != 0) {
                solarTime += TimeConstant.SECONDS_PER_DAY;
            }
            String solarTimeStr = DateUtil.getString(solarTime, new SimpleDateFormat("MM-dd"));
            solarList.add(solarTimeStr);
            try {
                lunarTime = DateUtil.getInt(CalendarUtil.timestamp2Lunar(solarTime), DateUtil.SDFDate);
            } catch (Exception e) {
                lunarTime = 0;
            }
            String lunarTimeStr = DateUtil.getString(lunarTime, new SimpleDateFormat("MM-dd"));
            lunarList.add(lunarTimeStr);
        }
        birthdayPojo.setSolarList(solarList);
        birthdayPojo.setLunarList(lunarList);
    }

    public static void parseProductSearchCondition(BoolQueryBuilder boolQueryBuilder, List<ConditionsEntityExt> productSerchConditions, String rel, String corpid, Integer subBusinessType) {
        if (Objects.isNull(productSerchConditions) || productSerchConditions.isEmpty()) {
            return;
        }
        BoolQueryBuilder childQueryBuilder = boolQuery();
        childQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(subBusinessType);
        for (ConditionsEntityExt condition : productSerchConditions) {
            Integer fieldType = condition.getFieldType();
            ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
            switch (xbbRefTypeEnum) {
                case STOCK_SEARCH:
                    conditionStock(conditionEnum, condition.getAttr(), condition, childQueryBuilder);
                    break;
                case WARNING_SEARCH:
                    if (Objects.equals(FieldTypeEnum.getFieldTypeEnum(fieldType).getBelong(), BelongEnum.WARNING.getAlias())) {
                        conditionWarning(fieldType, boolQueryBuilder);
                        boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                    } else {
                        if (Objects.equals(condition.getAttr(), "num") || Objects.equals(condition.getAttr(), FieldTypeEnum.BATCH_WAREHOUSE_ID.getAlias())) {
                            conditionStock(conditionEnum, condition.getAttr(), condition, boolQueryBuilder);
                        } else {
                            conditionStock(conditionEnum, condition.getAttr(), condition, childQueryBuilder);
                        }
                    }
                    break;
                case GUARANTEE_SEARCH:
                    conditionBatch(conditionEnum, condition.getAttr(), fieldType, condition, boolQueryBuilder);
                    break;
                default:
                    return;
            }
        }
        if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.WARNING_SEARCH) || Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.GUARANTEE_SEARCH)) {
            return;
        }
        IndexTypeEnum indexTypeEnum = null;
        switch (xbbRefTypeEnum) {
            case STOCK_SEARCH:
                indexTypeEnum = IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE;
                break;
            case WARNING_SEARCH:
                indexTypeEnum = IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE;
                break;
            case GUARANTEE_SEARCH:
                indexTypeEnum = IndexTypeEnum.IDX_SAAS_PRODUCT_STOCK_INFO;
                break;
            default:
                break;
        }
        childQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        if (Objects.nonNull(indexTypeEnum)) {
            HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(indexTypeEnum.getType(), childQueryBuilder, ScoreMode.Max);
            boolQueryBuilder.filter(hasChildQueryBuilder);
        }

    }

    /**
     * 为空数据
     * @param fieldType        需要检索的字段的字段类型
     * @param boolQueryBuilder
     * @param attr             需要检索的字段
     */
    public static void isNull(Integer fieldType, BoolQueryBuilder boolQueryBuilder, String attr) {
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldType);
        switch (fieldTypeEnum) {
            case TEXT:
            case TEXTAREA:
            case COMBO:
            case RADIO_GROUP:
            case COMBO_CHECK:
            case CHECKBOX_GROUP:
            case LINK_BUSINESS_SINGLE:
                BoolQueryBuilder boolQuery = boolQuery();
                boolQuery.should(boolQuery().mustNot(existsQuery("data." + attr)));
                boolQuery.should(boolQuery().filter(termQuery("data." + attr + ".keyword", "")));
                boolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(boolQuery);
                break;
            case DATAID:
                boolQueryBuilder.mustNot(existsQuery(attr));
                break;
            case USER:
            case DEPT:
            case NUM:
            case STAGE_RATIO:
            case DATETIME:
                boolQueryBuilder.mustNot(existsQuery("data." + attr));
                break;
            case ADDRESS:
                BoolQueryBuilder addressBoolQuery = boolQuery();
                addressBoolQuery.should(boolQuery().mustNot(existsQuery("data." + attr)));
                // 地址的省份为空时，即该值为空
                addressBoolQuery.should(boolQuery().filter(termQuery("data." + attr + "." + BusinessConstant.PROVINCE, "")));
                addressBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(addressBoolQuery);
                break;
            case SERIALNO:
                BoolQueryBuilder serialNoBoolQuery = boolQuery();
                serialNoBoolQuery.should(boolQuery().mustNot(existsQuery(attr)));
                serialNoBoolQuery.should(boolQuery().filter(termQuery(attr, "")));
                serialNoBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(serialNoBoolQuery);
                break;
            case LINK_DATA:
                BoolQueryBuilder linkDataBoolQuery = boolQuery();
                linkDataBoolQuery.should(boolQuery().mustNot(existsQuery("data." + attr)));
                linkDataBoolQuery.should(boolQuery().filter(termQuery("data." + attr + ".keyword", 0)));
                linkDataBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(linkDataBoolQuery);
                break;
            default:
                BoolQueryBuilder defaultBoolQuery = boolQuery();
                defaultBoolQuery.should(boolQuery().mustNot(existsQuery("data." + attr)));
                defaultBoolQuery.should(boolQuery().filter(termQuery("data." + attr, "")));
                defaultBoolQuery.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.must(defaultBoolQuery);
                break;
        }
    }

    public static void nonNull(Integer fieldType, BoolQueryBuilder boolQueryBuilder, String attr) {
        ConditionsEntityExt condition = new ConditionsEntityExt();
        condition.setFieldType(fieldType);
        attr = addKeyWord(condition,attr);
        boolQueryBuilder.filter(existsQuery("data." +attr.replace(".keyword", "")));
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
        if (FieldTypeEnum.DATETIME.getType().equals(fieldType)
                || FieldTypeEnum.STAR.getType().equals(fieldType)
                || FieldTypeEnum.DEPARTMENTID.getType().equals(fieldType)
                || FieldTypeEnum.ADDTIME.getType().equals(fieldType)
                || FieldTypeEnum.LINK_DATA.getType().equals(fieldType)
                || FieldTypeEnum.UPDATETIME.getType().equals(fieldType)){
            boolQueryBuilder.filter(boolQuery().mustNot(termQuery("data." +attr,0)));
        }else if (FieldTypeEnum.getFieldTypeEnum(fieldType).getEsalias().equals(FieldTypeEnum.TEXT.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(fieldType).getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())
                || FieldTypeEnum.getFieldTypeEnum(fieldType).getEsalias().equals(FieldTypeEnum.UPLOAD.getEsalias())){
            boolQueryBuilder.filter(boolQuery().mustNot(termQuery("data." +attr,"")));
        }else if (!FieldTypeEnum.NUM.getEsalias().equals(fieldTypeEnum.getEsalias()) && !FieldTypeEnum.STAGE_RATIO.getEsalias().equals(fieldTypeEnum.getEsalias())){
            boolQueryBuilder.filter(boolQuery().mustNot(termQuery("data." +attr,"")));
        }
    }

    /**
     * aggName、字段名组装
     * @param fieldAttrPojo    字段属性
     * @param isSingle         是否单表
     * @param field            字段名
     * @param aggName          聚合别名
     * @return 组装后的attr
     * @throws XbbException error
     */
    private static String getAggNameAndField(FieldAttrPojo fieldAttrPojo, boolean isSingle, StringBuilder field, StringBuilder aggName) throws XbbException {
        String attr = fieldAttrPojo.getAttr();
        Integer type = fieldAttrPojo.getFieldType();
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(type);
        if (type == null || fieldTypeEnum == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, "字段类型不可为空");
        }
        boolean inData = setInData(type);
        if (fieldTypeEnum.getEsalias().equals(FieldTypeEnum.TEXT.getEsalias()) || fieldTypeEnum.getEsalias().equals(FieldTypeEnum.ADDRESS.getEsalias())) {
            attr = attr + ".keyword";
        }
        if (inData && isSingle) {
            field.append("data.");
        }
        field.append(attr);
        String oldReplace = attr;
        aggName.append(oldReplace.replace(".keyword", "")).append("&").append(type);
        return attr;
    }


    public static int getTeamIdx(ChartEntity chartEntity, Long formId) {
        JSONArray slaveSourcePojo = chartEntity.getSlaveSources();
        SlaveSourcePojo driverPojo = JSON.toJavaObject(chartEntity.getDriverSources(), SlaveSourcePojo.class);
        if (Objects.equals(driverPojo.getFormId(), formId)) {
            return 1;
        } else {
            List<SlaveSourcePojo> slaveSourceList = slaveSourcePojo.toJavaList(SlaveSourcePojo.class);
            for (int k = 0; k < slaveSourceList.size(); k++) {
                SlaveSourcePojo sourcePojo = slaveSourceList.get(k);
                if (Objects.equals(sourcePojo.getFormId(), formId)) {
                    return  k + 2;
                }
            }
        }
        return 1;
    }

    /**
     * 获取是否是单表 单表返回true
     * @param chartEntity
     * @return
     */
    public static boolean getSingle(ChartEntity chartEntity){
        return  !Objects.equals(chartEntity.getMuti(), BasicConstant.ZERO);
    }

    /**
     * 获取是否设置同环比，一个统计字段设置了就返回true
     * @param chartEntity
     * @return boolean
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/7 19:41
     * @version 1.0
     */
    public static boolean isYearChain(ChartEntity chartEntity){
        List<FieldAttrPojo> fieldAttrPojoList = new ArrayList<>();
        if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode()) || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.TARGET_CHART.getCode())) {
            fieldAttrPojoList = JSON.parseArray(chartEntity.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
        } else {
            if (CollectionsUtil.isNotEmpty(chartEntity.getChartValue())) {
                fieldAttrPojoList = JSON.parseArray(chartEntity.getChartValue().toJSONString(), FieldAttrPojo.class);
            }
            // 双轴图
            if (CollectionsUtil.isNotEmpty(chartEntity.getChartValueSecond())) {
                fieldAttrPojoList.addAll(JSON.parseArray(chartEntity.getChartValueSecond().toJSONString(), FieldAttrPojo.class));
            }
        }

        for (FieldAttrPojo fieldAttrPojo : fieldAttrPojoList) {
            JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
            if (CollectionsUtil.isNotEmpty(advancedComputing) && Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.YEAR_CHAIN.getAlias())) {
                return true;
            }
        }

        return false;
    }

    public static Boolean getSortFlag(Map<String, String> sortMap, String aggName) {
        Boolean asc = null;
        if (sortMap != null) {
            String ascStr = sortMap.get(aggName);
            asc = ascStr == null ? null : Objects.equals(ascStr, StringConstant.SORT_ASC_TAG);
        }
        return asc;
    }

    public static Map<String, String> statisticSummaryAggs(SearchSourceBuilder sourceBuilder, List<FieldAttrPojo> summaryAttrList, ChartEntity chartEntity) throws XbbException {
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        boolean isSingle = getSingle(chartEntity);
        Map<String, String> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isNotEmpty(summaryAttrList)) {
            for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
                StringBuilder field = new StringBuilder();
                StringBuilder aggName = new StringBuilder();
                String formId = fieldAttrPojo.getFormId().toString();
                String attr = getAggNameAndField(fieldAttrPojo, isSingle, field, aggName);
                String fieldResult = field.toString();
                if (attr.contains("count")) {
                    fieldResult = "id";
                    if (formIdAttr != null && formIdAttr.size() > 0) {
                        fieldResult = formIdAttr.getJSONObject(formId).getString(StringConstant.DATA_ID);
                        aggName = new StringBuilder(formId).append(aggName);
                    }
                    String name = aggName.append("&").append(fieldAttrPojo.getGroupIndex()).toString();
                    AggregationBuilder countAggregationBuilder = AggregationBuilders.count(name).field(fieldResult);
                    sourceBuilder.aggregation(countAggregationBuilder);
                    param.put(fieldAttrPojo.getAttr(), name);
                } else if (attr.contains("computedField") && Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldAttrPojo.getFieldType())) {
                    List<String> fieldsList = new ArrayList<>();
                    //判断单表还是多表，拼script
                    JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                    String formula = formulaInfo.getString("formula");
                    //公式转换
                    try {
                        formula = getString(sourceBuilder, formIdAttr, isSingle, fieldsList, formulaInfo, formula, formId);
                    } catch (XbbException e) {
                        LOG.error("计算字段的公式格式有问题", e);
                        throw e;
                    }
                    String name = aggName.append("&").append(fieldAttrPojo.getGroupIndex()).toString();
                    String aggType = fieldAttrPojo.getAggType();
                    AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                    switch (aggTypeEnum) {
                        case SUM:
                            SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(name).script(new Script(formula));
                            sourceBuilder.aggregation(sumAggregationBuilder);
                            break;
                        case AVG:
                            AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(name).script(new Script(formula));
                            sourceBuilder.aggregation(avgAggregationBuilder);
                            break;
                        case MAX:
                            MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(name).script(new Script(formula));
                            sourceBuilder.aggregation(maxAggregationBuilder);
                            break;
                        case MIN:
                            MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(name).script(new Script(formula));
                            sourceBuilder.aggregation(minAggregationBuilder);
                            break;
                        case COUNT:
                            ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(name).script(new Script(formula));
                            sourceBuilder.aggregation(countAggregationBuilder);
                            break;
                    }
                } else {
                    String name = aggName.append("&").append(fieldAttrPojo.getGroupIndex()).toString();
                    String aggType = fieldAttrPojo.getAggType();
                    AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
                    switch (aggTypeEnum) {
                        case SUM:
                            SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(name).field(fieldResult);
                            sourceBuilder.aggregation(sumAggregationBuilder);
                            break;
                        case AVG:
                            AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(name).field(fieldResult);
                            sourceBuilder.aggregation(avgAggregationBuilder);
                            break;
                        case MAX:
                            MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(name).field(fieldResult);
                            sourceBuilder.aggregation(maxAggregationBuilder);
                            break;
                        case MIN:
                            MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(name).field(fieldResult);
                            sourceBuilder.aggregation(minAggregationBuilder);
                            break;
                        case COUNT:
                            ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(name).field(fieldResult);
                            sourceBuilder.aggregation(countAggregationBuilder);
                            break;
                    }
                    param.put(fieldAttrPojo.getAttr(), name);
                }
            }
        }
        sourceBuilder.size(0);
        return param;
    }

    /**
     * 子表单类型筛选组装
     * @param boolQueryBuilder es查询api
     * @param conditionEnum    筛选类型
     * @param condition        筛选详情
     * @author zhouwq
     * @date 2020/10/14 16:36
     */
    private static void subFormConditionSymbolChoose(BoolQueryBuilder boolQueryBuilder, ConditionEnum conditionEnum, ConditionsEntityExt condition) {
        String attr = condition.getAttr();
        String subFormAttr = "";
        //获取当前字段的attr 并去除父attr前缀
        if (attr.contains(StringConstant.POINT)) {
            String[] attrArray = attr.split("\\.");
            attr = attrArray[1];
            subFormAttr = attrArray[2];
        }
        condition.setAttr("data." + subFormAttr);
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery("attr.keyword", attr));
        commonConditionSymbolChoose(teamQueryBuilder, conditionEnum, condition);
        boolQueryBuilder.filter(JoinQueryBuilders.hasChildQuery("sub_form_data",teamQueryBuilder, ScoreMode.Max));
    }

    /**
     * 根据esalias判断是否是日期类型
     * @param fieldAttrEntity
     * @return boolean
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/7 20:49
     * @version 1.0
     */
    public static boolean isDateByEsalias(FieldAttrEntity fieldAttrEntity) {
        if (fieldAttrEntity == null) {
            return false;
        }
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldAttrEntity.getFieldType());
        if (fieldTypeEnum != null) {
            return Objects.equals(fieldTypeEnum.getEsalias(), StringConstant.DATE);
        }
        return false;
    }

    /**
     * com.xbongbong.saas.help.SaasListHelp#addressSearchCondition(com.xbongbong.paas.pojo.dto.FormDataListDTO)
     * 地址筛选条件
     *
     * @param conditions 参数
     * @return
     * @throws
     * @author hongxiao
     * @date 2019-07-05 09:17
     * @since v1.0
     * @version v1.0
     */
    public static void addressSearchCondition(List<ConditionsEntityExt> conditions, List<List<ConditionsEntityExt>> shouldConditionList) {
        List<ConditionsEntityExt> newAddressConditions = new ArrayList<>();
        // 公海池分组：省市区
        Map<String, ConditionsEntityExt> publicGroupAddressMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ConditionsEntityExt> publicGroupAddressConditions = new ArrayList<>();
        conditions = conditions != null ? conditions : new ArrayList<>();
        Iterator<ConditionsEntityExt> iterator = conditions.iterator();
        while (iterator.hasNext()){
            ConditionsEntityExt entityExt = iterator.next();
            if (Objects.equals(FieldTypeEnum.ADDRESS.getType(),entityExt.getFieldType())){
                List<Object> value = entityExt.getValue();
                if (CollectionUtils.isNotEmpty(value)) {
                    Object address = value.get(0);
                    if (Objects.nonNull(address) && address instanceof Map) {
                        JSONObject addressObj = JSON.parseObject(JSON.toJSONString(address));
                        List<Object> addressList = new ArrayList<>();
                        if (addressObj.containsKey(PaasConstant.PROVINCE)) {
                            addressList.add(addressObj.get(PaasConstant.PROVINCE));
                        }
                        if (addressObj.containsKey(PaasConstant.CITY)) {
                            addressList.add(addressObj.get(PaasConstant.CITY));
                        }
                        if (addressObj.containsKey(PaasConstant.DISTRICT)) {
                            addressList.add(addressObj.get(PaasConstant.DISTRICT));
                        }
                        if (addressObj.containsKey(PaasConstant.ADDRESS)) {
                            addressList.add(addressObj.get(PaasConstant.ADDRESS));
                        }
                        value = addressList;
                    }
                }
                String attr = entityExt.getAttr();
                String symbol = entityExt.getSymbol();
                Integer fieldType = FieldTypeEnum.TEXT.getType();
                String province;
                String city;
                String district;
                String addressDetail;
                String provinceAttr = attr + StringConstant.POINT + PaasConstant.PROVINCE;
                String cityAttr = attr + StringConstant.POINT + PaasConstant.CITY;
                String districtAttr = attr + StringConstant.POINT + PaasConstant.DISTRICT;
                String addressAttr = attr + StringConstant.POINT + PaasConstant.ADDRESS;
                ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(entityExt.getSymbol());
                if(Objects.isNull(conditionEnum)) {
                    iterator.remove();
                    continue;
                }
                switch (conditionEnum) {
                    case EQUAL:
                        if(value.size() > 0) {
                            province = value.get(0).toString();
                            ConditionsEntityExt provinceCondition = new ConditionsEntityExt(provinceAttr, "", fieldType, symbol, Collections.singletonList(province));
                            newAddressConditions.add(provinceCondition);
                        }
                        if(value.size() > 1) {
                            city = value.get(1).toString();
                            ConditionsEntityExt cityCondition = new ConditionsEntityExt(cityAttr, "", fieldType, symbol, Collections.singletonList(city));
                            newAddressConditions.add(cityCondition);
                        }
                        if(value.size() > 2) {
                            district = value.get(2).toString();
                            ConditionsEntityExt districtCondition = new ConditionsEntityExt(districtAttr, "", fieldType, symbol, Collections.singletonList(district));
                            newAddressConditions.add(districtCondition);
                        }
                        if(value.size() > 3) {
                            addressDetail = value.get(3).toString();
                            ConditionsEntityExt addressDetailCondition = new ConditionsEntityExt(addressAttr, "", fieldType, symbol, Collections.singletonList(addressDetail));
                            newAddressConditions.add(addressDetailCondition);
                        }
                        break;
                    case NOEQUAL:
                        if(value.size() > 2) {
                            district = value.get(2).toString();
                            ConditionsEntityExt districtCondition = new ConditionsEntityExt(districtAttr , "", fieldType, symbol, Collections.singletonList(district));
                            newAddressConditions.add(districtCondition);
                        } else if(value.size() > 1) {
                            city = value.get(1).toString();
                            ConditionsEntityExt cityCondition = new ConditionsEntityExt(cityAttr, "", fieldType, symbol, Collections.singletonList(city));
                            newAddressConditions.add(cityCondition);
                        } else if(value.size() > 0) {
                            province = value.get(0).toString();
                            ConditionsEntityExt provinceCondition = new ConditionsEntityExt(provinceAttr, "", fieldType, symbol, Collections.singletonList(province));
                            newAddressConditions.add(provinceCondition);
                        }
                        break;
                    case LIKE:
//                        if(value.size() > 0) {
//                            province = value.get(0).toString();
//                            List<String> attrList = Arrays.asList(provinceAttr,cityAttr,districtAttr,addressAttr);
//                            for(String newAttr : attrList) {
//                                List<ConditionsEntityExt> addressConditions = new ArrayList<>();
//                                ConditionsEntityExt addressCondition = new ConditionsEntityExt(newAttr, "", fieldType, symbol, Collections.singletonList(province));
//                                addressConditions.add(addressCondition);
//                                shouldConditionList.add(addressConditions);
//                            }
//                        }
                        break;
                    case NOLIKE:
                        if(value.size() > 0) {
                            province = value.get(0).toString();
                            ConditionsEntityExt provinceCondition = new ConditionsEntityExt(provinceAttr, "", fieldType, symbol, Collections.singletonList(province));
                            ConditionsEntityExt cityCondition = new ConditionsEntityExt(cityAttr, "", fieldType, symbol, Collections.singletonList(province));
                            ConditionsEntityExt districtCondition = new ConditionsEntityExt(districtAttr, "", fieldType, symbol, Collections.singletonList(province));
                            ConditionsEntityExt addressCondition = new ConditionsEntityExt(addressAttr, "", fieldType, symbol, Collections.singletonList(province));
                            newAddressConditions.add(provinceCondition);
                            newAddressConditions.add(cityCondition);
                            newAddressConditions.add(districtCondition);
                            newAddressConditions.add(addressCondition);
                        }
                        break;
                    case EMPTY:
                        ConditionsEntityExt provinceCondition = new ConditionsEntityExt(provinceAttr, "", fieldType, symbol, Collections.singletonList(""));
                        ConditionsEntityExt cityCondition = new ConditionsEntityExt(cityAttr, "", fieldType, symbol, Collections.singletonList(""));
                        ConditionsEntityExt districtCondition = new ConditionsEntityExt(districtAttr, "", fieldType, symbol, Collections.singletonList(""));
                        ConditionsEntityExt addressCondition = new ConditionsEntityExt(addressAttr, "", fieldType, symbol, Collections.singletonList(""));
                        newAddressConditions.add(provinceCondition);
                        newAddressConditions.add(cityCondition);
                        newAddressConditions.add(districtCondition);
                        newAddressConditions.add(addressCondition);
                        break;
                    case NOEMPTY:
//                        List<String> attrList = Arrays.asList(provinceAttr,cityAttr,districtAttr,addressAttr);
//                        List<ConditionsEntityExt> addressConditions = new ArrayList<>();
//                        for(String newAttr : attrList) {
//                            ConditionsEntityExt newAddressCondition = new ConditionsEntityExt(newAttr, "", fieldType, symbol, Collections.singletonList(""));
//                            addressConditions.add(newAddressCondition);
//                        }
//                        shouldConditionList.add(addressConditions);
                        break;
                    default:
                        break;
                }
                if (!Objects.equals(ConditionEnum.NOEMPTY, conditionEnum) && !Objects.equals(ConditionEnum.LIKE, conditionEnum)) {
                    iterator.remove();
                }
            } else if(Objects.equals(PaasConstant.PROVINCE, entityExt.getAttr()) || Objects.equals(PaasConstant.CITY, entityExt.getAttr())
                    || Objects.equals(PaasConstant.DISTRICT, entityExt.getAttr())) {
                // 公海池分组：省、市、区
                publicGroupAddressMap.put(entityExt.getAttr(), entityExt);
                iterator.remove();
            }
        }

        // 公海池分组：省、市、区
        if(!publicGroupAddressMap.isEmpty()) {
            for(Map.Entry<String, ConditionsEntityExt> entry : publicGroupAddressMap.entrySet()) {
                ConditionsEntityExt entityExt = entry.getValue();
                List<Object> value = entityExt.getValue();
                String subAttr = entityExt.getAttr();
                String symbol = entityExt.getSymbol();
                Integer fieldType = FieldTypeEnum.TEXT.getType();
//                String province;
//                String city;
//                String district;
                String attr = CustomerManagementEnum.ADDRESS.getAttr() + StringConstant.POINT + subAttr;
                ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(entityExt.getSymbol());
                if(Objects.isNull(conditionEnum)) {
                    continue;
                }
                switch (conditionEnum) {
                    case EQUAL:
                    case NOEQUAL:
                    case LIKE:
                    case NOLIKE:
                    case IN:
                    case NOIN:
                        ConditionsEntityExt hasValueCondition = new ConditionsEntityExt(attr, "", fieldType, symbol, value);
                        publicGroupAddressConditions.add(hasValueCondition);
                        break;
                    case EMPTY:
                    case NOEMPTY:
                        ConditionsEntityExt noValueCondition = new ConditionsEntityExt(attr, "", fieldType, symbol, Collections.singletonList(""));
                        publicGroupAddressConditions.add(noValueCondition);
                        break;
                    default:
                        break;
                }
            }
        }
        conditions.addAll(publicGroupAddressConditions);
        conditions.addAll(newAddressConditions);
    }
}
